Live demo — data resets daily at 03:00 UTC. Nothing you enter is saved. Server UI →

product: assert audience: test-developer authority: normative

Variable System

Declaration

variables:
  supply_voltage: 12.0    # numeric
  channel: 1              # integer
  device_ready: false     # boolean
  fw_version: ""          # string

Templating

Syntax: {{variable_name}} — no dots, no expressions inside braces.

Works in: parameters values, outputs values, measurement.value, measurement.name, prompt.message, prompt.title.

DOES NOT work in: precondition, repeat.condition, enabled — use bare variable names there.

What does NOT work in templates

What a developer might try Why it fails
"{{voltage + offset}}" Arithmetic not supported — compute in C#/Python before returning
"{{RAIL_{{railname}}}}" Nested references not supported
"{{measurement.value}}" Dot notation not supported — use flat variable names
"{{value}}" (expecting scalar return) Implicit scalar variable is result, not value

Output variables

Step return values are stored automatically. The outputs block renames them:

outputs:
  rail_3v3: "{{measured_voltage}}"   # store return key "measured_voltage" as "rail_3v3"

Output variables are stored in a single execution-scoped variable store — there IS NO per-runner scope. A variable set by a runner: dotnet step IS immediately available to a subsequent runner: python step.

Scope: every variable belongs to one execution

The test's variables: block, step outputs, prompt inputs, sub-sequence parameters: and values set from the debugger all belong to the execution that set them. A name is looked up in this order:

  1. values written during the run (step outputs, prompts, parameters, debugger edits);
  2. the test's own variables: block;
  3. station-wide values (none are written by the station today).

Two executions running at the same time on a parallel station (MaxParallelExecutions > 1) never see each other's variables, even when both tests declare the same names. Everything an execution holds is removed when it ends, whatever its verdict.

Before 2.6.0 the variables: block was written to the station-wide scope. Concurrent runs that declared the same name overwrote each other, and a run could read a value that an earlier run of a different test had declared. Anything left there by those versions is cleared when the station starts.

Sub-sequence invocations start fresh

Sub-sequences share the caller's scope (see Standalone / Composite Test Pattern), but each invocation of a sub-sequence file starts from that file's own defaults, not from what its previous invocation left behind. When the same file is invoked again (once per connector, say):

  • a variable the file declares in variables: that the caller did not provide goes back to its declared value;
  • a variable the file's steps created (an output, a runner return value such as result) is removed, so a template reading it before a step writes it again resolves to nothing - and a measurement reading it is not acquired (see Measurement Patterns) instead of republishing the previous invocation's value;
  • parameters: are then applied as before, and override declared defaults.

What the caller owns is untouched: a variable the test declares, or an earlier step set before the file was first invoked, is inherited on every invocation with whatever value it has now - including a value the sub-sequence itself updated last time (the "connect once" pattern). A variable the sub-sequence created that the caller has since overwritten is the caller's and is not reset either. Between invocations the caller can still read everything the last invocation left; the reset happens when the file is next entered.

Built-in variables

Variable Set by Description
__iteration__ Repeat engine Zero-based loop counter inside repeat: blocks
__execution_id__ Executor GUID of the current test execution

Station Configuration Variables (cfg.*)

The station configuration store (held in Orchestra) holds hardware-specific settings that differ between stations. At test start the engine reads all configuration entries for the current station, merges global and station-local values, then injects each entry as a cfg.* variable.

Priority Scope StationId in DB Use
1 (lowest) Global NULL Shared defaults across all stations
2 (highest) Station-local e.g. "ST-01" Per-station overrides

Station-local values WIN over global values when the same key exists in both scopes.

Always-injected key

Variable Description
cfg.station_id Resolved station identity. Auto-injected — NOT a DB entry.

Key naming convention

UPPER_SNAKE_CASE for hardware-address keys (e.g. DMM_VISA, PSU_COM_PORT). lower_snake_case for numeric tuning values (e.g. dmm_timeout_ms).

Usage example

- name: "Initialise DMM"
  runner: dotnet
  runner_type: net10.0
  assembly: "InstrumentDrivers.dll"
  class: "InstrumentDrivers.DmmDriver"
  method: "Connect"
  parameters:
    dmm_address: "{{cfg.DMM_VISA}}"
    dmm_timeout_ms: "{{cfg.DMM_TIMEOUT_MS}}"

A full snapshot of the merged station config IS saved as JSONB on every TestExecution row — enabling post-mortem queries about which config was active when a run failed.

Using cfg.* in a precondition

cfg.* MUST NOT be used directly in precondition:. To branch on a cfg.* value, read it into a bare variable first:

variables:
  dmm_visa: ""

setup:
  - name: "Read station config"
    runner: dotnet
    runner_type: net10.0
    assembly: "InstrumentDrivers.dll"
    class: "InstrumentDrivers.Config"
    method: "GetDmmVisa"
    parameters:
      dmm_visa: "{{cfg.DMM_VISA}}"
    outputs:
      dmm_visa: "{{result}}"

steps:
  - name: "Connect to DMM"
    precondition: "dmm_visa != ''"   # safe — bare variable
    ...

Execution Metadata Variables (exec.*)

Injected at test start from the API execution request:

Variable Always set? Description
exec.serial_number Serial number of the DUT under test
exec.operator_id When provided ID of the operator who started the test
exec.station_id Same value as cfg.station_id
exec.tag.<Key> Per tag One entry per tag key

Well-known tag keys

Key UI label Typical value
ProductId Product ID PCB-100, ESH10000121
ProductRevision Revision Rev C, A
BatchId Batch ID BATCH-Q1-2025
Notes Notes Free text

Any key not in this list gets a dynamic text input in the UI.

MES Metadata Variables (mes.*)

When a test is started through MES routing:

Variable Description
mes.correlation_id Correlation ID linking this execution to the MES routing option

Additional mes.* keys may be present depending on the MES driver. Check with the system integrator for the full set available in your environment.

Namespace summary

Namespace Example In {{}} In precondition:
bare {{voltage}}
__iteration__ {{__iteration__}}
__execution_id__ {{__execution_id__}}
cfg. {{cfg.DMM_VISA}}
cfg.station_id {{cfg.station_id}}
exec. {{exec.serial_number}}
exec.tag. {{exec.tag.ProductId}}
mes. {{mes.correlation_id}}
An unhandled error has occurred. Reload

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.