product: maestro 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.
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 database 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}} |
✅ | ❌ |