Wandelbots Docs

Type to search the documentation

Press ESC to close⌘K to open

The @nova.program decorator

Last updated: July 21, 2026

Relevant for: Developer

Complete guide to the @nova.program decorator for creating NOVA robot programs with controller configuration, visualization, and parameter exposure.

The @nova.program decorator is the foundation of creating robot programs in Wandelbots NOVA. It transforms your Python function into a NOVA-managed robot program, exposing it through the API and making it discoverable by applications to run them.

After writing and decorating your program, you must register it through NOVAx to make it available in the Program Operator and other Wandelbots NOVA applications. More information on registration is provided at the end of this document.

For detailed and in-depth descriptions on how to write a program with the Python SDK, see the Wandelbots NOVA Python SDK documentation.

Decorator functionality

The @nova.program decorator serves as a developer’s manifest. It provides program metadata, the controller configuration, validation rules, and optional visualization settings.

Bare

import nova

@nova.program
async def simple_program():
    print("Hello World!")

The program ID defaults to the function name (simple_program).

@nova.program(
    id="my_robot_program",
    name="My Robot Program",
    description="A program that performs pick and place operations"
)
async def main():
    print("Hello from My Robot Program!")

Parameters

id (str, optional)

Unique identifier for the program across your NOVA instance. Must not contain spaces or special characters.

If not provided, the function name is used as the ID.

@nova.program(id="pick_and_place_v2")

name (str, optional)

Human-readable display name shown in the Program Operator interface and other NOVA applications.

@nova.program(
    id="pick_place",
    name="Pick and Place Operation"
)

description (str, optional)

Detailed description of what the program does, helpful for documentation and operator guidance.

@nova.program(
    id="palletizing",
    name="Palletizing Application",
    description="Stacks boxes in a 4x4 pattern on EUR pallets with configurable layer height"
)

preconditions (ProgramPreconditions, optional)

Defines required robot controllers and their configurations. The Program Operator validates these preconditions before allowing program execution.

from nova import api
from nova.cell import virtual_controller
from nova.program import ProgramPreconditions

@nova.program(
    id="ur_welding",
    name="UR Welding Program",
    preconditions=ProgramPreconditions(
        controllers=[
            virtual_controller(
                name="ur10e",
                manufacturer=api.models.Manufacturer.UNIVERSALROBOTS,
                type="universalrobots-ur10e",
            )
        ],
    ),
)
async def welding_program():
    # Your program logic
    pass

The preconditions ensure that:

  • Required controllers are present in the cell
  • Only specified devices are opened and monitored
  • Safety features like emergency stop handling are properly configured

viewer (Viewer, optional)

Enables program visualization. The most common viewer is nova.viewers.Rerun(), which provides 3D visualization of robot motion.

When enabled, the visualization might impact the cycle time.

3D visualization

@nova.program(
    id="motion_test",
    viewer=nova.viewers.Rerun()
)
async def test_motion():
    # Any plan or execute calls are automatically logged to Rerun
    pass

Advanced with detailed analysis

@nova.program(
    id="complex_motion",
    viewer=nova.viewers.Rerun(
        show_details=True,              # Show detailed analysis panels
        show_safety_zones=True,          # Visualize safety zones
        show_collision_link_chain=True,  # Show collision checking
        show_collision_tool=True,        # Display tool collision geometry
        show_safety_link_chain=True,     # Show safety link chain
        tcp_tools={
            "vacuum": "assets/vacuum_cup.stl",
            "gripper": "assets/parallel_gripper.stl"
        }
    )
)

The Rerun viewer captures and visualizes robot trajectories and motion paths, TCP poses and transformations, motion group states, planning requests and responses, collision scenes and safety zones, tool geometries attached to specific TCPs.

Learn more about visualization in the Rerun documentation.

Omniverse viewer

@nova.program decorator accepts a viewer protocol specified here.

You can implement your own viewer by implementing this protocol, e.g., an Omniverse viewer.

Configurable function parameters

To make function parameters available to operators, make them available in the Program Operator by exposing variables in your program code. Use type hints and default values for better UI generation.

  1. Add parameters to your program function.
  2. Re-run the registration script to update the Program Operator with the new parameter.
  3. Access the Parameters tab in the Program Operator UI.
@nova.program(
    id="example_program",
    name="Example Robot Program",
    # ... other configuration
)
async def start(tcp_velocity_limit: int):
    # Use the parameter in your robot movements
    speed: MotionSettings = MotionSettings(tcp_velocity_limit=tcp_velocity_limit)

The Program Operator generates appropriate UI controls based on your parameter types using JSONForms.

Numeric inputs with constraints

Renders as number input fields with minimum and maximum validation.

The ge (greater than or equal) and le (less than or equal) constraints ensure safe operating ranges.

from pydantic import Field

async def program(
    speed: int = Field(default=1000, ge=100, le=5000),
    precision: float = Field(default=0.5, ge=0.1, le=2.0)
):
    pass

Boolean toggles

Renders as a checkbox or toggle switch.

async def program(enable_safety_check: bool = True):
    pass

String inputs

Renders as a text input field.

async def program(operation_mode: str = "standard"):
    pass

Enums

Renders as a dropdown selection menu.

from enum import Enum

class Material(str, Enum):
    STEEL = "steel"
    ALUMINUM = "aluminum"
    PLASTIC = "plastic"

async def program(material: Material = Material.STEEL):
    pass

Required

Parameters without default values are marked as required. A value must be provided before starting the program.

Use this to force operators to input critical configuration values.

async def program(
    workpiece_id: str,                    # Required - no default value
    cycle_count: int = 100                # Optional - has default value
):
    pass

Next steps

You’re ready to run the program. This includes registering it with NOVAx and executing it from the Program Operator.