Skip to content

Design prompt content

A good prompt tells the operator what changed, what they must inspect or do, and what each available action means. Keep the main instruction short; use detail rows for values the operator needs to verify.

A complete prompt resolves to these fields:

Field Requirement and behavior
title Required, non-empty dialog title.
message Required main instruction. It may be an empty string when the details carry all necessary information.
severity Required: info, success, warning, or error.
size Optional: sm, md, or lg; defaults to sm.
details Optional label/value rows. Each row may have a when condition.
actions Required list of one to 16 operator actions.
allow_abort Required boolean controlling whether Ctrl shows an Abort button that aborts the current LinuxCNC task.
hal.pins Optional machine-facing values and results. HAL-backed prompts require a trigger.

Choose severity for the state being communicated, not for visual emphasis. Use error for a condition that prevents the intended operation, warning for a condition requiring caution or intervention, success for a completed positive outcome, and info for neutral guidance.

Use a larger size when translations, detail rows, or the decision itself need more room. Do not use size as a substitute for editing an overly long instruction.

Every action has an identifier, a visible label, and an intent:

prompts:
recovery:
# ...
actions:
- id: retry
label: Retry
intent: primary
- id: stop
label: Stop operation
intent: danger

The id is a stable machine-facing value. It is the key used by HAL on_action mappings and the value returned to software producers. Keep it independent of the translated label.

Action intents describe presentation and meaning:

Intent Use it for
primary The main expected continuation.
secondary A valid alternative or non-primary choice.
danger A destructive or hazardous choice that deserves extra visual weight.

Set allow_abort: true to add a danger-styled Abort button. Pressing it sends LinuxCNC a task-abort command, closes the prompt with an aborted result, and does not apply any HAL on_action mapping. For a HAL-backed prompt, the machine logic must still lower the trigger to release the request.

Set allow_abort: false when the operator must answer through one of the declared actions. This removes the Abort button from the prompt; it does not prevent LinuxCNC from being aborted through other controls or system behavior.

Add variable to a readable in or io pin, then use the same name in templated content:

prompts:
spindle-temperature:
# ...
hal:
pins:
show:
direction: in
type: bit
trigger: rising
temperature:
direction: in
type: float
variable: temperature
message: Spindle temperature is {{ temperature }} °C

Variables may appear in:

  • title and message;
  • detail label, value, and when;
  • action label; and
  • every translation of those localized fields.

Every custom variable used by the content must have exactly one readable HAL pin binding, and every declared variable must be used. A missing, duplicate, or unused binding prevents the broker from starting.

The broker captures all readable variable pins together on the trigger’s rising edge. Changing temperature while the prompt is active does not change the displayed value. Lower the trigger, update the value pins, and raise the trigger to submit a new snapshot.

Details keep supporting values aligned and scannable:

prompts:
tool-change:
# ...
details:
- label: Requested tool
value: "T{{ tool_number }}"
- label: Tool comment
value: "{{ tools[tool_number].comment }}"
when: tools[tool_number].comment != ''

The when field is an expression without {{ }} delimiters. The row is omitted when the expression evaluates to false. Its label and value are rendered only when the row is visible.

Prompt content uses a restricted Jinja syntax. It supports substitutions, indexing, attribute reads, comparisons, boolean expressions, and {% if %} conditions. It rejects loops, includes, macros, assignments, function calls, and arbitrary filters. Undefined variables are errors.

Two read-only values are supplied without HAL bindings:

Value Available data
is_lathe true for an XZ lathe configuration and false otherwise.
tools[number] exists, number, diameter, and comment for a tool-table entry.

Looking up a tool number that is not in the table returns exists: false, the requested number, a zero diameter, and an empty comment. Check exists when absence must be distinguishable from a valid zero value.

For example:

prompts:
tool-change:
# ...
message: >-
Load tool T{{ tool_number }}
{% if tools[tool_number].comment != '' %}
({{ tools[tool_number].comment }})
{% endif %}

Like HAL variables, tool data, lathe status, and machine-unit scale are frozen when the request is submitted.

Use the only supported filter, linear, for values expressed in LinuxCNC machine units:

prompts:
position-check:
# ...
details:
- label: Position
value: "{{ position | linear }}"

The default preserves the configured machine unit and includes its suffix. It shows three decimal places for millimetres and four for inches.

Pass mm or in when the prompt deliberately needs a particular display unit:

prompts:
position-check:
# ...
details:
- label: Position
value: "{{ position | linear('mm') }}"

Do not apply linear to an already converted value. The broker treats the input as a value in the machine’s native linear units and converts it only when the requested display unit differs.

title, message, detail label, and action label may be a plain string or a locale map:

prompts:
fixture-check:
# ...
title:
en: Verify fixture
pl: Sprawdź przyrząd
actions:
- id: continue
label:
en: Continue
pl: Kontynuuj
intent: primary

When Ctrl requests pl-PL, the broker uses the pl-PL translation when it is present. Otherwise it tries pl, then en, then the first entry in the locale map. The same fallback order applies to every requested locale.

Plain strings are used for every locale. A detail value is always one templated string rather than a locale map; keep translated explanatory text in its label or in the main message.

When Ctrl changes locale while a prompt is active, the broker rerenders the same captured request. The prompt identity and queue position do not change.