Skip to content
Getting Started

How to Add Operator Prompts to Hardware Tests

Operator prompts pause automated tests for manual steps. Learn how to add prompts with text input, choices, and timeouts to OpenHTF tests.

JJulien Buteau
beginner7 min readMarch 14, 2026

How to Add Operator Prompts to Hardware Tests

Many manufacturing tests mix automated measurements with manual steps. The operator needs to load a DUT, flip a switch, perform a visual inspection, or enter a value. OpenHTF handles this through operator prompts that pause the test, display a message, and optionally collect input. This guide covers how to add prompts to your tests and display them through the TofuPilot operator UI.

When to Use Prompts

SituationExample
DUT loading"Place the board in the fixture and close the clamp"
Visual inspection"Check for solder bridges on connector J1"
Manual measurement"Read the label and enter the lot code"
Physical action"Press the reset button on the DUT"
Go/no-go decision"Does the LED illuminate green?"
Safety check"Verify the safety cover is closed"

Prompts keep the operator in the test flow. They see the instruction in the same interface that shows measurements and pass/fail results.

Prerequisites

  • Python 3.10+
  • OpenHTF installed (pip install openhtf)
  • TofuPilot Python SDK installed (pip install tofupilot)

Step 1: Add a Simple Prompt

The simplest prompt displays a message and waits for the operator to acknowledge it.

prompted_test.py
import openhtf as htf
from openhtf.plugs import user_input


@htf.plug(prompts=user_input.UserInput)
def phase_load_dut(test, prompts):
    """Wait for the operator to load the DUT."""
    prompts.prompt(
        "Place the board in the test fixture. "
        "Close the clamp and press Enter."
    )

The test pauses at this phase until the operator responds. In TofuPilot's operator UI, the prompt appears as a card with the message and an acknowledgment button.

Step 2: Collect Text Input

Add text_input=True to collect a value from the operator. The returned string can be stored as a measurement.

prompted_test.py
@htf.plug(prompts=user_input.UserInput)
@htf.measures(
    htf.Measurement("lot_code").with_args(docstring="Operator-entered lot code"),
)
def phase_enter_lot_code(test, prompts):
    """Ask the operator to scan or type the lot code."""
    lot = prompts.prompt(
        "Scan the lot code barcode on the packaging.",
        text_input=True,
    )
    test.measurements.lot_code = lot

Step 3: Use Prompts for Visual Inspection

Combine a prompt with a measurement to record the operator's inspection result.

prompted_test.py
@htf.plug(prompts=user_input.UserInput)
@htf.measures(
    htf.Measurement("visual_result").equals("PASS"),
)
def phase_visual_inspection(test, prompts):
    """Operator checks for cosmetic defects."""
    result = prompts.prompt(
        "Inspect the board under magnification. "
        "Type PASS if no defects found, or FAIL if defects are present.",
        text_input=True,
    )
    test.measurements.visual_result = result.strip().upper()

Step 4: Add Prompts Between Automated Phases

Mix prompted and automated phases in the same test. The operator sees a seamless flow: automated measurements run, then a prompt appears, then more automated measurements.

prompted_test.py
from openhtf.util import units


@htf.measures(
    htf.Measurement("supply_voltage_V")
    .in_range(minimum=4.9, maximum=5.1)
    .with_units(units.VOLT),
)
def phase_power_check(test):
    """Automated: measure supply voltage."""
    test.measurements.supply_voltage_V = 5.01


@htf.plug(prompts=user_input.UserInput)
def phase_flip_board(test, prompts):
    """Ask operator to flip the board for bottom-side testing."""
    prompts.prompt(
        "Flip the board over so the bottom side faces up. "
        "Press Enter when ready."
    )


@htf.measures(
    htf.Measurement("bottom_connector_resistance_mOhm")
    .in_range(maximum=100)
    .with_units(units.OHM),
)
def phase_bottom_test(test):
    """Automated: measure bottom-side connector resistance."""
    test.measurements.bottom_connector_resistance_mOhm = 38.5

Step 5: Connect to TofuPilot

Wire all phases together. Prompted phases render in the TofuPilot operator UI automatically. No extra configuration needed.

prompted_test.py
from tofupilot.openhtf import TofuPilot

test = htf.Test(
    phase_load_dut,
    phase_enter_lot_code,
    phase_power_check,
    phase_visual_inspection,
    phase_flip_board,
    phase_bottom_test,
)

with TofuPilot(test):
    test.execute(test_start=lambda: input("Scan serial: "))

Best Practices

PracticeWhy
Keep prompt text short (1-2 sentences)Operators scan, they don't read paragraphs
Use imperative verbs ("Place", "Press", "Scan")Clear instructions reduce errors
One action per promptDon't ask the operator to do three things at once
Validate operator inputUse .equals() or .matches_regex() on the measurement
Put prompts at natural breaksBetween automated sequences, not in the middle of a measurement
Avoid unnecessary promptsEvery prompt adds cycle time. Automate what you can.

More Guides

Put this guide into practice