Protocols and Bindings
Protocols are the top-level executable units in Culsma.
Protocols
A protocol has a name and a statement body.
protocol FlowCytometryProtocol {
let target = tube(label = "Target", capacity = 100uL);
}Culsma also supports parameters and explicit returns:
protocol Prepare(sample, volume = 10uL) returns (output) {
let output = tube(label = "Output");
return output;
}The general shape is:
protocol Name(optional_params) returns (optional_names) {
statements...
}Protocol names are case-sensitive identifiers.
Parameters
Protocol parameters are declared in the protocol header:
protocol Prepare(sample, volume = 10uL) {
...
}Parameters may have defaults. When another protocol calls a parameterized protocol, named arguments bind to parameter names.
Module.Prepare(sample = source, volume = 5uL);Missing, unknown, duplicate, or redeclared call arguments are plan-stage diagnostics because call-frame expansion happens while building the plan.
Parameters can also drive plan-static control surfaces. For example, a protocol parameter may set a repeat count, a schedule boundary, an environment duration, or a static if condition:
protocol DiluteBatch(cycles = 3, hold_time = 10min, run_cleanup = true) {
let target = tube(label = "Target", capacity = 100uL);
let feed = tube(label = "Feed", capacity = 100uL);
repeat cycle in schedule(start = 1, end = cycles, step = 1) {
target << [feed:1uL];
}
if run_cleanup {
with env(thermal = 4C, duration = hold_time) {
hold(target);
}
}
}Local Bindings
let creates a new protocol-local binding.
let source = tube(label = "Source", capacity = 100uL);Later statements in the same protocol can refer to source.
let target = tube(label = "Target", capacity = 100uL);
target << [source:5uL];let is local to the protocol body. It does not define a global material namespace and does not automatically leak into called protocols.
Assignment
Assignment updates an existing local binding:
x = 10uL;Assignment is intentionally narrow. It updates protocol-local values; it does not mutate container material state. Material movement is written with <<.
Assignment allows:
- booleans
- integers
- text
- quantities
- restricted result-member paths such as
data_ref.result.field
It does not allow assignment to container refs, group refs, general indexed targets, or arbitrary object fields.
Returns
A protocol can return an expression:
return output;It can also use named return bindings:
return output = output_tube;Returning a container returns a container reference payload. It does not collapse the result to a string name or a derived report row.
Returning a group returns a container_group_ref payload. Explicit groups and plate selector groups preserve member order:
protocol SelectedWells returns (wells) {
let plate96 = plate(label = "QPCR96", format = "96well", carrier_id = "PlateA");
return wells = plate96[A1:A2];
}Cross-Protocol Calls
The clearer form for calling another protocol is:
Module.ProtocolName(arg = value);The referenced protocol is expanded into concrete plan steps. Reference errors and cycles are reported by plan diagnostics.
Source Includes and Imports
Culsma source files may use top-level loading declarations:
include "path/to/file.culs";
import StdlibModule;include loads source files. import resolves library modules. The example protocol examples stay single-file; multi-file workflows can be introduced separately.
