Time and Sequence
Overview
This section covers the ordering and timing of tasks within a workflow. It explains methods for controlling the sequence and constraining task execution to control exactly when tasks are completed.
Time Constraints
Time constraints define how two tasks are related in terms of their start and end times. They control task sequencing and timing to maintain order in workflows. These constraints are evaluated during planning and replanning.
Available Constraint Types
START_TO_END: The second task cannot finish before the first task starts (ensures gap between start of first and end of second).START_TO_START: The second task cannot start before the first task starts (minimum delay between task starts).END_TO_END: The second task cannot finish before the first task finishes (both constrained to end in order).END_TO_START: The second task cannot start before the first task finishes (enforces sequential execution with optional gap).CONSISTENCY: Ensures timing consistency between two tasks (used in cross-batch constraints).
plate_incubation = ActionTask(...)
dispense_reagent = ActionTask(...)
# Defining the time constraint for incubation
incubation_constraint = TimeConstraint(
id="incubate-to-dispense-constraint",
constraint_type=TimeConstraintType.END_TO_START,
start_task=plate_incubation,
end_task=dispense_reagent,
min_duration=600,
max_duration=900,
enable_detailed_coverage_calculation=True,
auto_ignore_if_broken=False,
)
Note
Detailed coverage calculation
enable_detailed_coverage_calculation lets you trade planning detail for speed on large workflows.
If a TimeConstraint spans many tasks, leaving this True (default) may slow pausing/planning; set it to False to improve performance.
Time Constraints are added to a Workflow object. See Workflow.
In the event a time constraint is broken (for example due to an error or a large difference between estimated and real time) an error will be raised with mitigation options. See Error Handling.
- class linq.workflow.TimeConstraint(*, id: str, constraint_type: TimeConstraintType, start_task: ActionTask, end_task: ActionTask, min_duration: int | None, max_duration: int | None)
A time constraint for a sequence of tasks.
- id: str
Unique ID for this time constraint.
- constraint_type: TimeConstraintType
Time constraint type.
- start_task: ActionTask
First task in the sequence that the constraint applies to.
- end_task: ActionTask
Last task in the sequence that the constraint applies to.
- min_duration: int | None
Minimum duration allowed for the sequence.
- max_duration: int | None
Maximum duration allowed for the sequence.
Max Idle Time
Max idle time sets the maximum duration labware can be left unattended during a workflow. This is important for labware containing sensitive materials like cells or samples that require timely handling to maintain their integrity.
Labware Type Level
Define max idle time as a default for all labware of a specific type:
assay_plate = LabwareType(
id="nest_flat_bottom_96_well_plate",
max_idle_time=30 # Max idle time in seconds
)
Labware Instance Level
Override the labware type’s max idle time for a specific labware instance:
sample_plate = Labware(
id="sample_plate_1",
labware_type=assay_plate,
starting_location=LabwareLocation(instrument=stacker, slot=1),
max_idle_time=60, # Override: 60 seconds for this instance (takes precedence over type-level)
)
Instance-level max_idle_time takes precedence over the labware type’s setting. If neither is specified, there is no idle time constraint.
Instrument Blocks
Instrument blocks prevent any task from executing on a specific instrument from a specified task until another specified task. This is useful when an instrument’s state is temporarily modified (e.g. holding a cap) meaning it is not strictly being used for a task, but is otherwise occupied.
A typical use case is an uncapping task which requires an instrument to hold a cap until the next task is completed. The specific uncapper can be blocked from use until a task completes.
Instrument blocks are added to a Workflow object. See Workflow.
- class linq.workflow.InstrumentBlock(*, start_task: ActionTask, end_task: ActionTask)
An instrument block instruction, keeping the instrument from being used between two tasks.
Dependencies
Task dependencies ensure that certain tasks are completed before others can begin, maintaining proper task order. The first task of a chain of tasks will not have any dependencies. Any kind of task can have a dependency or be the target of a dependency.
Labware input and output creates labware dependencies automatically. In other words, if a given task has specified a previous task as containing labware that it needs as input, a dependency does not need to be specified. See Labware Flow.
Additional dependencies can be manually configured as follows:
dispense_reagent = ActionTask(...)
load_plate = ActionTask(
id="load_plate",
# ...
dependencies=[dispense_reagent],
)
You can have multiple dependencies for the same task. Note that any type of task, e.g. a CodeTask or an ActionTask, can be specified in the dependency array or made dependent on any other task.
dependencies=[dispense_reagent, move_data],
Time Estimates
Time estimates approximate how long each task will take, used by the planner to optimize task scheduling and predict workflow duration.
If the actual time is different from the estimated time for a task when executing on hardware, a replan may be triggered. See Planning and Validation.
dispense_reagent = ActionTask(...)
load_plate = ActionTask(
id="load_plate",
# ...
time_estimate=20,
)
Transport Matrix and Robots
In workflows, transport actions are implicit, meaning they happen automatically between tasks (see Tasks and Transport). The transport matrix allows you to configure estimated timings for movements between workbenches and robots. These timings are used during planning to calculate transport tasks when the workflow is executed.
The default_transport_time serves as the fallback time for any unspecified transport paths. However, you can customize the timing between specific robots by defining transport paths. This lets you control how long it takes to move between robots while accounting for transport layer movements, ensuring more accurate planning.
workcell = Workcell(
# ...
transport_matrix=TransportMatrix(
default_transport_time=20,
paths=[
TransportPath(source="robot_1", destination="robot_1", time=55),
TransportPath(source="robot_2", destination="robot_2", time=20),
TransportPath(source="robot_1", destination="robot_2", time=90),
TransportPath(source="robot_2", destination="robot_1", time=100),
],
),
)
- class linq.workcell.TransportMatrix(*, default_transport_time: int, paths: list[TransportPath])
The transport matrix contains all estimates for transport times between benches.
- default_transport_time: int
Default transport time if no specific estimate for a path is given.
- paths: list[TransportPath]
List of paths describing the time to transport labware from one bench to another.
Transport Timing with Predefined Configurations
When you reference a predefined transport configuration (instead of using inline timing estimates), the planning and timing behavior changes.
Transport Config Priority and Flexibility
You can define both inline transport_matrix and reference a predefined transport_config in the same Workcell. When both are specified and the planner uses transport_concurrency="transport_v3", the planner uses actual timings from the transport_config instead of estimates from transport_matrix.paths.
This allows for flexible deployment:
Start simple: Define workflows with inline
transport_matrixestimatesMigrate gradually: Add
transport_configreference at deployment time without modifying workflow codeUse measured timings: When
transport_concurrency="transport_v3"is configured, the planner uses the transport config’s actual timings for more accurate scheduling
Impact on Planning
When a transport config is specified in your workcell and planning is configured with transport_concurrency="transport_v3":
Planning uses the config’s timings — The planner uses actual transport timings from the config instead of estimates from
transport_matrix.pathsMore accurate schedules — V3 configs provide measured timings, reducing planning uncertainty
Consistent behavior — All workflows using the same workcell see identical transport behavior
Versioning support — Changes to transport config create new versions, allowing rollback if needed
Note
When transport_concurrency="transport_v3" is used with both transport_config and transport_matrix.paths specified, the planner uses timings from the transport_config. For other transport_concurrency values, the behavior depends on the planning configuration. See Planning and Validation for details on transport_concurrency options.
For detailed guidance on defining, creating, and managing transport configurations, see Tasks and Transport.