Skip to main content
A policy is any callable that maps observations to actions:
def policy(obs: Dict[str, Tensor]) -> Tensor:
    ...
Use @rfx.policy to make a function deployable from the CLI.

Minimal policy

my_policy.py
import torch
import rfx

@rfx.policy
def hold_position(obs):
    return torch.zeros(1, 6)  # hold still (SO-101 has 6 joints)
Deploy:
uv run rfx deploy my_policy.py --robot so101

Named joint control

Use MotorCommands to build actions from joint names instead of raw tensor indices:
@rfx.policy
def grasp(obs):
    return rfx.MotorCommands(
        {"gripper": 0.8, "wrist_pitch": -0.2},
        config=rfx.SO101_CONFIG,
    ).to_tensor()
See MotorCommands for the full API.

Stateful policies

A policy can be any callable, including a class with state. @rfx.policy wraps a factory function — the returned callable becomes the policy:
import torch
import rfx

class TrackingPolicy:
    def __init__(self, target):
        self.target = target

    def __call__(self, obs):
        error = self.target - obs["state"]
        return 0.1 * error

@rfx.policy
def track():
    return TrackingPolicy(target=torch.zeros(1, 6))

Torch and tinygrad

LoadedPolicy handles torch / tinygrad conversion automatically at deploy time. Policies can be authored in either framework as long as the callable contract holds.