kualia.ai documentation

Teach your robot new tricks

kualia turns a sentence into a trained robot skill. Pick a MuJoCo robot, describe the trick in any language, and alia writes a training task, builds the world the trick needs and checks it. You train a policy in simulation, watch it practise in your browser, iterate in versions and export an ONNX policy for the real robot.

Twelve robots, or yours

Five realistic robots from MuJoCo Menagerie (Go2, Spot, OP3, G1, Panda), seven fast-training classics from a cart-pole to a 3D humanoid, or your own MJCF / URDF.

A world for the trick

Ball, box, step, ramp, wall, goal, target, knob and button: a world planner picks what the trick needs and alia places them as real physics bodies.

13 automated checks

Every task version is tested in a sandbox before a single training step is paid for.

Watch it learn

PPO training with a live reward chart, checkpoint videos and a 3D replay of every checkpoint.

AI review & versions

Each run gets an analysis with concrete changes; every change becomes a new, comparable version.

ONNX out

A deterministic policy with observation normalisation baked in. Runs with onnxruntime + numpy.

kualia never generates robot physics

Tasks are built on a fixed, validated MuJoCo model. alia writes only the task layer: what the robot is rewarded for, when an episode ends, what counts as success and which objects are in the world. It cannot change the robot’s bodies, joints or actuators, and those rules are re-applied on every change.

No code is required. Everything alia writes is visible, though: the Plan page shows the full Python task, and this documentation explains exactly how it is structured, so you can read it, reason about it and ask for precise changes.

Getting started

Quick start: your first trick in five minutes

The fastest route from a blank page to a trained policy. Use a small robot for your first run; the workflow is identical for the big ones.

  1. Open “Teach a new trick”

    Sign in and open the Dashboard. The start screen is Teach a new trick: choose a robot, describe the trick, adjust the training settings.
  2. Pick a robot that learns quickly

    InvertedPendulum (balance a pole) and Reacher (a two-link arm) learn in tens of thousands of steps. Walker2d is pre-selected, but a biped needs far more practice, and the realistic robots (Go2, Spot, OP3, G1) need millions of steps. See Robots.
  3. Describe the trick in one sentence

    Or press Try an example, which fills the robot, the trick and a measurable success criterion. For example, on InvertedPendulum:

    brief
    Balance the pole upright while keeping the cart near the center.
    Success: keep the pole within 0.1 radians of upright for 5 seconds.
    
  4. Keep the default settings

    Success criterion Let kualia pick, safety Standard, reward Dense shaping, difficulty Easy. The Estimated cost panel shows the plan estimate and the price of a first 10K-step run before you click.
  5. Build the training plan

    A world planner first decides which objects the trick needs (if any). alia then writes the reward, termination and success rules, runs the 13 checks and repairs failures on its own (up to four attempts). This takes a minute or two.
  6. Review the plan and the world

    On Plan & world, read Your trick and What success looks like (the task restated in one sentence and a short step list of a successful episode), open the reward explanation, press play in the 3D world for a zero-torque drop test, and confirm the checks read 13 / 13. Anything you want changed, tell alia.
  7. Start a first run

    Choose First try · 10K steps and press Start training. Watch the reward chart and the checkpoint film strip fill in. A short run is a sanity check: does the robot move sensibly, do episodes last?
  8. Read the results, then iterate or export

    Open the run’s results: evaluation episodes, failure cases and an AI analysis with proposed changes. Train longer, create the next version from the analysis, or go to Export and download the ONNX policy.

Short runs are for checking the task, not for mastering it

10K steps is enough for a cart-pole to improve and for you to see whether the reward points the right way. Bigger robots need hundreds of thousands to millions of steps; the Learn it budget suggests a typical number for each robot.

Getting started

Core concepts

A handful of words are used throughout the Studio and these docs.

Robot
A MuJoCo model: one of the twelve built-in robots or a model you uploaded. Its physics stay fixed.
Trick
What you want the robot to learn, in your words, plus the optional success criterion, safety level, reward style and starting difficulty. Together they form the brief.
Task
The Python training environment alia writes from the brief: a Gymnasium Env with the reward, termination and success rules and, if needed, world objects. Also called the task code.
Training plan
The structured summary of the task shown on the Plan page: the trick in one sentence, what success looks like step by step, reward design, success criteria, failure conditions, observation signals, action space and curriculum stages.
World
What the robot practises in: the floor plus the objects declared in the task’s SCENE. The world planner decides which objects a trick needs. The same world is used in the checks, in training and in the browser.
Policy
The neural network that maps what the robot senses (observations) to motor commands (actions). Training improves it; export turns it into an ONNX file.
Run
One training job with a step budget on one task version. A run has a reward curve, checkpoints, evaluation episodes, a trained model and an AI analysis.
Checkpoint
A snapshot of the policy recorded during a run (untrained, 25 %, 50 %, 75 %, final) with a video and a 3D trajectory.
Version
Every change to the task creates a new numbered version (v1 is the one built from your brief). Runs are pinned to the version they trained on, so results stay comparable; any older version can be made current again.
Training steps
What a run spends. Every plan includes a monthly number of them; alia, the assistant, is included too. See Plans & training steps.

The brief kualia sends

The form on Teach a new trick is assembled into a plain-text brief. Seeing it helps when you later ask alia for changes:

brief sent to alia
Walk forward at 1 m/s on flat ground.

Success criterion: Maintain a forward speed between 0.8 and 1.2 m/s for 3 seconds without falling.

Avoid: Avoid falling, jerky motion and excessive joint torque.

Reward style: Use dense reward shaping that rewards progress every step.

Implement the success criterion explicitly in info['is_success'].

Getting started

The Studio, step by step

A trick moves through five screens. alia is available on every one of them and can change the task at any point.

ScreenWhat you do there
1 · Teach a new trickPick a built-in robot or import one (MJCF/URDF), describe the trick (up to 1,000 characters), choose success criterion, safety level, reward style and starting difficulty. A task summary splits your sentence into steps and the cost panel estimates plan and training prices.
2 · Plan & worldRead your trick for this version, what success looks like, the training plan (six cards), the reward explanation and the generated task code. Inspect the world in the 3D simulator (World / Robot / Observations tabs, physics drop test). See the 13 checks, pick a practice budget and start training.
3 · TrainingWatch the live simulation, the checkpoint film strip (0 / 25 / 50 / 75 % and final), the learning-progress chart, the training log and run statistics. Stop the run, train the version again, or keep training from the previous model.
4 · ResultsRuns & versions lists every run of every version: design a new run with alia, train again as it is, compare two runs, make an older version current. Each run has its own results page with the best policy rollout, evaluation episodes, failure cases and the AI analysis.
5 · ExportTry the exported policy live in the browser, review its input/output schema, control rate and checksum, download the ONNX file and copy a minimal on-robot inference loop.

Inside a project, stages 2–5 are the tabs of the Studio’s stage bar. Plan & world is where you land after building a plan, and where you review every assistant change before training it.

Open the Dashboard →

Build a task

Robots

Every task is pinned to one MuJoCo robot. Start with one of the eighteen built-in models — tiny maker robots first — or import your own robot description.

There are three shelves of built-in robots. Joints is the number of actuators (the size of the action vector), Obs the size of the robot’s own observation, Control the rate at which the policy acts, and Learn it the step budget the Studio suggests for learning a real skill with PPO (a rough order of magnitude, not a guarantee).

Tiny & maker robots

Real, desk-sized robots that people build and buy: the Open Duck Mini biped, Stanford’s ToddlerBot, the ROBOTIS OP3, the LeRobot SO-101 and low-cost arms, a two-servo Dynamixel arm and Bitcraze’s Crazyflie quadcopter. Their models come from MuJoCo Menagerie and the Open Duck project; kualia trains them on its own servers today. The arms and the quadcopter learn in a run or two; the bipeds need millions of steps.

RobotKindJointsObsControlTierLearn itNotes
DuckOpen Duck Mini v2 biped164350 Hzhard~2MThe open-source 3D-printed desk biped (Apache-2.0): legs, neck, head and antennas. Starts from the Playground’s standing pose (base ≈ 0.15 m).
ToddlerbotStanford ToddlerBot humanoid309950 Hzhard~5MA 0.5 m open-source humanoid (MIT) with arms, waist and neck; starts from its “home” pose (base ≈ 0.31 m). Heavy meshes, long budgets.
OP3ROBOTIS small humanoid205150 Hzhard~5MA ~50 cm hobby humanoid with legs, arms and head. Ships no keyframe: it starts standing straight at zero joint angles (base ≈ 0.30 m).
SO101SO-101 arm + gripper61250 Hzmedium~300KThe LeRobot desktop arm (Apache-2.0): five joints and a gripper, fixed base, ~0.4 m reach. Reach, push, press on the table.
LowCostArmlow-cost arm + gripper61250 Hzmedium~200KAlexander Koch’s 3D-printed arm (Apache-2.0): five joints and a gripper, ~0.25 m reach; starts from its “home” pose.
Dynamixel2R2-link Dynamixel arm2450 Hzeasy~50KTwo Dynamixel servos on a 0.55 m stand (MIT). The simplest real arm: reach a target in minutes.
Crazyflienano quadcopter41150 Hzmedium~300KBitcraze’s 27 g quadcopter (MIT): thrust plus roll/pitch/yaw moments. A zero action is the hover trim; the floor is a crash.

Bigger real robots (MuJoCo Menagerie)

Four models of larger real robots. Go2 trains here; Spot, G1 and Panda are previews: you can plan a task, run the checks and start short tries (capped at 30,000 steps), but a real gait or grasp on them needs GPU-scale training, which kualia does not offer yet. Ask for it with the GPU runs waitlist button in the Studio.

RobotKindJointsObsControlTierLearn itNotes
Go2Unitree robot dog123550 Hzhard~3MA real consumer quadruped. Uses Menagerie’s position-controlled go2_mjx variant; starts from its standing “home” pose (base ≈ 0.27 m).
SpotBoston Dynamics quadruped123550 Hzhard~3MPreview, sim only. The industrial quadruped, heavier and steadier than Go2; starts standing (base ≈ 0.46 m). Runs capped at 30K steps.
OP3ROBOTIS small humanoid205150 Hzhard~5MA ~50 cm hobby humanoid with legs, arms and head. Ships no keyframe: it starts standing straight at zero joint angles (base ≈ 0.30 m).
G1Unitree humanoid296950 Hzhard~10MPreview, sim only. A full-size humanoid that starts from its “stand” pose (pelvis ≈ 0.79 m). Runs capped at 30K steps.
PandaFranka arm + gripper81850 Hzmedium~500KPreview, sim only. 7-axis research arm plus one gripper actuator, fixed base; starts from its “home” pose. Runs capped at 30K steps.
  • Always the kualia_sim route. There is no Gymnasium environment for these robots, so every task subclasses MjcfRobotEnv with ROBOT_ASSET = menagerie_asset("Go2") (the model’s scene: robot, floor and light), with or without world objects.
  • They start standing. Episodes begin from the model’s standing keyframe (home, or stand for G1), and each position actuator’s range is re-centred on that keyframe, so a zero action holds the pose. The browser simulator uses the same start pose and controls.
  • All joints are position-controlled: an action is a joint target around the standing pose, not a torque. Panda’s eighth actuator is the gripper.

Classic robots (Gymnasium)

The MuJoCo models of the Gymnasium v5 suite. They are simplified bodies that train fast, which makes them ideal for learning the workflow and for quick experiments.

RobotKindJointsObsControlTierLearn itNotes
InvertedPendulumcart-pole1425 Hzeasy~30KCart on a rail balancing a pole. The base task already ends when the pole tilts more than 0.2 rad.
Reacher2-link arm21050 Hzeasy~100KPlanar two-link arm reaching a target. Fixed base: it cannot fall.
Hopperone-legged hopper311125 Hzmedium~300KSingle leg that must hop forward without falling.
Walker2dplanar biped617125 Hzmedium~500KThe classic two-legged planar walker.
HalfCheetahplanar runner61720 Hzmedium~300KCannot fall and never terminates on its own; pure speed and gait.
Antquadruped810520 Hzhard~1MFour legs, contact-rich dynamics (observation includes contact forces).
Humanoid3D humanoid1734867 Hzhard~2MFull 3D biped. High-dimensional and unstable; needs long training.

Choosing a first robot

Dynamixel2R, InvertedPendulum and Reacher give feedback within a single short run; SO101 and LowCostArm are the quickest real arms. Hopper, Walker2d and HalfCheetah are good for locomotion tricks once you know the workflow. Panda is the quickest of the realistic robots for reaching, pressing and turning. Ant, Humanoid, Go2, Spot, OP3 and G1 are powerful but need long, expensive runs: at $0.10 per 1,000 steps a 3M-step Go2 budget costs $300, and a 10K-step run on G1 will not produce a walking robot.

Menagerie models and licenses

The realistic robots come from MuJoCo Menagerie by Google DeepMind, pinned to one commit, with the robots’ physics unchanged. Each model keeps its own license file and copyright notice: Go2 and G1 (Unitree Robotics) and Spot are BSD-3-Clause; OP3 and Panda are Apache-2.0.

Bring your own robot (MJCF / URDF)

Import a robot from Robots → Import your robot (also reachable from the robot shelf on Teach a new trick). kualia loads it in MuJoCo, validates it and renders a preview. A validated robot appears on the shelf marked yours and can be used exactly like a built-in one.

RequirementDetails
FileA .zip (model + meshes/textures), a MuJoCo .xml or a .urdf. Maximum 60 MB upload, 200 MB and 600 files after extraction.
Allowed files.xml .urdf .stl .obj .msh .skn .png .jpg .jpeg .mtl plus text/metadata (.txt .md .json .yaml .yml). Other files are not extracted.
Model choiceIn a zip, kualia prefers an MJCF whose root is <mujoco> (a MuJoCo Menagerie-style scene.xml is ideal), then a URDF.
PathsMesh and include paths must be relative to the upload. Absolute and .. paths are rejected; URDF package:// URIs are rewritten to relative paths.
BaseAuto (MJCF as declared, URDF fixed), Floating (legged or mobile robot that can fall; a free joint is added if missing) or Fixed (arm or mechanism bolted to the ground).
ActuatorsMJCF is simulated as-is. URDFs carry no actuators, so kualia adds one position servo (kp = 20) per hinge/slide joint. A model with no actuated joints is rejected.
FloorA ground plane is added when the model has none.

Validation then builds the robot in the task runtime and runs two 400-step rollouts (holding the pose, and random actions). The report lists joints, actuators (position or torque control), total mass, timestep, observation size and control rate.

  • Errors (robot is marked needs validation and cannot be selected): no actuators, non-finite state during a rollout, exploding state, or the simulation probe failing.
  • Warnings: more than 64 actuators (slow on CPU), physics timestep above 0.01 s, total mass under 10 g or over 500 kg (check units, e.g. a URDF in millimetres), or the robot falling within 0.5 s while holding its pose.

Uploaded robots always use the kualia_sim runtime: the policy acts at 50 Hz by default (the task can set CONTROL_HZ), every actuator is normalised to [-1, 1], and the observation is the robot’s joint positions (without the world x/y of a floating base) and velocities. If your MJCF ships a keyframe (ideally named home or stand; otherwise the first one is used), episodes start from it and position actuators are centred on it, exactly as for the Menagerie robots.

Build a task

Describing a trick

The brief is the single biggest lever on whether training works. Describe one skill that the robot can physically do, with a result you could measure.

What makes a good brief

  • One skill at a time. “Walk forward, turn around and walk back” is three skills. Teach the first, then extend it in later versions.
  • Measurable. A distance, speed, height, angle or time: “travel 3 m within 10 s without falling”. If you leave the success criterion to kualia, it picks one of these.
  • Reachable from the start pose. Every robot starts near the origin, in its default pose (the realistic robots: standing). A trick that needs a different starting state has to say so.
  • Say what is in the world, in your own words. “Kick the ball”, “climb the stairs”, “tighten the screw”, “ring the doorbell”, in any language: the world planner maps them to the nine object types (a screw becomes a knob, a doorbell a button) and tells you what it cannot simulate.
  • Fit the body. Reacher has no legs, HalfCheetah cannot fall over, the planar robots (Hopper, Walker2d, HalfCheetah) only move in a vertical plane, and Panda is an arm bolted to the floor: it reaches, pushes, presses and turns, but does not walk.
BriefWhy it works (or not)
Walk forward at 1 m/s on flat ground.
Success: 0.8–1.2 m/s for 3 s without falling.
good One skill, a measurable speed band, sensible for Walker2d.
Kick the ball into the goal.good Names a ball and a goal, so both become real objects in the world.
Push the box onto the orange mark.good Box plus a target marker; a clear end state for Ant.
Hop up the two steps.good Two step objects for Hopper; progress is height and distance.
Turn the knob two full turns.good A knob for Panda, and object_turns gives a number to reward and a clear success test.
Vidayı sık. (Turkish: tighten the screw)good Understood in any language: the screw becomes a knob, and the Plan page says so.
Do something cool.weak Nothing to measure, so nothing to reward.
Walk to the kitchen and open the fridge.weak The world only contains the nine object types; there is no kitchen, fridge or door to open.
Jump rope.partly Ropes cannot be simulated. The planner says so, and the robot learns to jump rhythmically in place instead.
Balance on one leg, then do a backflip.split it Two very different skills; train them as separate versions.

Training settings

SettingOptionsWhat it changes
Success criteriaLet kualia pick (default) · I’ll define it…Your criterion goes into the brief verbatim; otherwise kualia asks for one measurable criterion reachable from the reset pose. Either way it is implemented in info["is_success"].
Safety levelRelaxed · Standard (default) · StrictAdds an “Avoid:” line: unstable states only / falling, jerky motion, excessive torque / plus self-collision and joint-limit hits, preferring smooth, energy-efficient motion.
Reward styleDense shaping (default) · Goal-basedDense rewards progress every step and learns faster; goal-based gives a clear completion bonus plus light shaping.
Starting difficultyEasy (default) · Medium · HardEasy means short episodes and forgiving thresholds; Hard means tighter tolerances and more variation. Also feeds the difficulty estimate on the Plan page.

Tip

Your draft is saved in the tab while you type, so you can leave to import a robot and come back to it.

Build a task

alia

alia writes the task from your brief and changes it when you chat with it. It works on the task layer only; the robot rules are injected into every request.

What it generates

For a robot task, the world planner first decides which objects the trick needs. Then one request returns both the training plan (a structured spec: the trick in one sentence, a 3–5 step success scenario, reward terms, success criteria, termination and truncation conditions, observation and action components, curriculum stages) and the complete task code. The code then runs through the 13 checks. If any fail, alia is shown the failures and repairs the code, up to four attempts, always continuing from the best-scoring version so a bad fix can never replace a better one.

The spec’s trick and success_scenario are what the Plan page shows as Your trick · v<n> and What success looks like. Every new version restates both, so they always describe the current task; when the trick has changed since your first brief, the card also shows “First asked: …”.

How it picks the route

There are two ways to build a task on a robot, and the choice is made before any code is written:

SituationRouteWhat the code looks like
You uploaded the robotkualia_simA subclass of MjcfRobotEnv with ROBOT_ASSET pointing at your validated model.
Realistic robot (Go2, Spot, OP3, G1, Panda)kualia_simMjcfRobotEnv with ROBOT_ASSET = menagerie_asset("Go2"), always, with or without a SCENE.
Classic robot, and the world plan has objectskualia_simMjcfRobotEnv on the same robot model via gym_asset("Walker2d"), with a SCENE. Only this route is offered, so an object can never be faked in Python.
Classic robot, no objectsGymnasium wrapperA gym.Env that creates the robot with gym.make("Walker2d-v5") and adds reward, termination and success on top of its observation and info keys.

Whether there are objects is what the world planner decides from the trick (the first paragraph of the brief). For chat changes, the objects route is used when the planner decides on objects, your message names one, or the task already has a SCENE; if a Gymnasium-route task gains objects, alia rewrites it on MjcfRobotEnv, keeping the reward idea and episode rules. For the Gymnasium route alia is given measured facts about each robot (observation indices, info keys, when the base environment already terminates) so that thresholds hold at the reset pose; for the kualia_sim route it gets where objects can go on that robot and, for the realistic robots, the start height and joint layout.

Changing the task by chat

Open alia from any Studio screen (Edit plan, Change the world, Change with alia). Each message is handled in one of two ways:

  • Question: an answer, nothing changes, no new version.
  • Change: the world planner re-plans the objects for the task after your message, then alia returns a change summary, the updated plan (with a restated trick and success scenario) and code, and any breaking changes (for example a different observation size). All 13 checks run again; if any fail, the same auto-fix loop as the first build repairs them (up to three attempts, keeping the best-scoring code). A new version is saved with the summary, which also carries the planner’s note on what stands in for what and what cannot be simulated, and the reply shows each check as a pass/fail chip.

If checks still fail after the automatic fixes, use Ask assistant to fix on the Plan page: it sends the failing checks with their details and asks for a fix that keeps everything else unchanged. Training cannot start until every check passes; the server refuses the run otherwise.

Versions are cheap and safe

Every change is a new version, and runs remember which version they trained on. You can always go back: Make current on the Runs & versions page restores an older version’s code and plan and re-runs its checks. After a rollback, the next change gets the next free version number, so nothing is overwritten.

Good requests

Be specific and quantitative, and change one thing at a time so the next run tells you something:

  • “Double the weight of the forward-velocity term and add a 0.1 penalty per step while the torso pitch exceeds 0.5 rad.”
  • “Move the ball to x = 1.5 m and give it a jitter of 0.3 m in x and y.”
  • “Add a goal 4 m ahead and reward the ball moving toward it instead of the ball’s speed.”
  • “End the episode when the ball rolls behind the robot.”
  • “Shorten episodes to 500 steps and make the success threshold 2 m instead of 3 m.”
  • “Why do most episodes end after about 20 steps?” (a question: no new version)

After a run, the AI analysis writes a ready-made instruction; Create v<n> from the analysis or Apply the AI suggestions sends it to alia for you. alia panel can also propose suggestions of its own.

Build a task

The world planner

Before alia writes a robot task, and again on every chat change, a world planner decides which physical objects the trick needs. It reads meaning, not keywords, so you can describe the trick in your own words and language.

The decision is binding: the code writer is told which objects the SCENE must contain, and the checks enforce it.

What it decides

  • Which objects, from the nine types (ball, box, step, ramp, wall, goal, target, knob, button), one entry per object and at most 8. Tricks about the robot’s own body (walk, run, jump, balance, flip, dance, turn) get no objects: distances are measured from the robot itself, so no target is added just to mark one.
  • A note on your words. Everyday things are mapped to the closest type: a screw, bolt, valve or tap is a knob, a doorbell or switch a button, a cup a small box, a table a raised step, stairs several steps of increasing height. The note says so plainly.
  • What cannot be simulated. Liquids, cloth, ropes, other robots, people or fine finger dexterity are left out, with a short explanation of what the robot will learn instead.
  • Where they go, in one sentence, using the robot’s placement facts.
You writeObjectsNote shown to you
Walk forward without fallingnone—
Climb three stairs and come back downstep × 3The stairs are three steps of increasing height.
Tighten a screw · vida sıksınknobThe screw is a knob; tightening it means turning its lever clockwise.
Ring the doorbellbuttonThe doorbell is a push button.
Carry the cup to the tablebox, stepThe cup is a small box and the table is a raised platform.
Jump rope · ipten atlasınnoneA rope can’t be simulated; the robot learns to jump rhythmically in place.

Where you see it

The note and the “cannot be simulated” line appear under Your trick on the Plan page, and after a chat change they are added to the version’s change summary. The decision is stored with the task’s spec (kualia.objects, kualia.note, kualia.unsupported), and the Objects start clear check fails while the SCENE lacks a planned object type.

On a chat change the planner sees the current world and returns the full list of objects after the change, so a request like “add a second ball” or “remove the wall” is planned against what is already there. If the planner call fails, kualia falls back to keyword matching on the trick (English and Turkish words for ball, box, stairs/steps, ramp, wall and goal), keeping the objects already in the world on a chat change. The planner is part of the plan or change request and billed with its usage.

Build a task

Task code

A task is a Gymnasium environment in a single Python file. You never have to write one, but knowing the shape makes it easy to read the generated code and ask for precise changes.

The kualia_sim runtime (MjcfRobotEnv)

Tasks with world objects, tasks on the realistic robots and tasks on uploaded robots subclass kualia_sim.MjcfRobotEnv. ROBOT_ASSET names the model: gym_asset("Walker2d") for a classic robot, menagerie_asset("Go2") for a realistic one, or your uploaded model. The base class owns everything that could break the physics: loading the model, adding the SCENE objects, mapping actions to actuators, the control rate, assembling observations, rendering and seeding. The task overrides five hooks:

HookReturnsDefault
compute_reward(self, action)float, per stepforward velocity + ALIVE_BONUS (1.0) − CTRL_COST (0.001) × Σ action²
is_terminated(self)boolfloating base: base below FALL_HEIGHT_RATIO (0.5) × start height, or upside down (upright < 0). Fixed base: never.
extra_observation(self)array or NoneNone. Task features appended to the observation (a command, a phase…). It is also called once while the base measures the observation size, so it must only read robot and object state, never self.observation_space, and return the same length every time.
is_success(self)bool, read at episode endmoved more than 1 m forward without terminating
on_reset(self)Nonenothing. Randomise targets or commands here with self.np_random.

Robot state available inside the hooks:

AttributeMeaning
base_positionworld position of the robot’s root body (x, y, z), metres
base_heightabsolute height of the root body
initial_base_heightroot height at the start pose (read-only)
x_positionroot x (forward)
forward_velocityx velocity of the root, per control step
base_velocitylinear velocity of the root body [vx, vy, vz], world frame, m/s
base_angular_velocityangular velocity of the root body [wx, wy, wz], world frame, rad/s
upright1 = upright, 0 = on its side, −1 = upside down
base_orientationroot quaternion (w, x, y, z)
joint_positions / joint_velocitiesthe robot’s joints (objects excluded)
max_steps, dt, np_randomepisode cap, control period in seconds, seeded RNG

Class attributes a task may tune: CONTROL_HZ (50), ALIVE_BONUS (1.0), CTRL_COST (0.001), FALL_HEIGHT_RATIO (0.5), RESET_NOISE (0.01, uniform noise on joint positions and velocities at reset, around the start pose: the model’s standing keyframe when it has one). Keyword arguments passed to __init__ become attributes, which is how curriculum knobs are expressed. The base class ignores attempts to reassign the observation space, the action space or the start height, and replaces a non-finite reward with −10 and ends the episode.

A complete task, using the object helpers from World objects:

kick_the_ball.py · kualia_sim route
import numpy as np
from kualia_sim import MjcfRobotEnv, gym_asset


class KickTheBall(MjcfRobotEnv):
    ROBOT_ASSET = gym_asset("Walker2d")   # the built-in Walker2d model, physics unchanged
    CONTROL_HZ = 125
    SCENE = [
        {"type": "ball", "name": "ball", "pos": [1.0, 0.0], "jitter": [0.2, 0.2]},
        {"type": "goal", "name": "goal", "pos": [4.0, 0.0]},
    ]

    def __init__(self, render_mode="rgb_array", max_steps=1000, **kwargs):
        super().__init__(render_mode=render_mode, max_steps=max_steps, **kwargs)

    def _ball_to_goal(self):
        d = self.object_position("goal") - self.object_position("ball")
        return float(np.hypot(d[0], d[1]))

    def on_reset(self):
        self.prev_ball_to_goal = self._ball_to_goal()

    def compute_reward(self, action):
        approach = -0.5 * self.object_distance("ball")         # walk to the ball
        now = self._ball_to_goal()
        progress = 10.0 * (self.prev_ball_to_goal - now)      # ball moved toward the goal
        self.prev_ball_to_goal = now
        touch = 0.2 if self.robot_touches("ball") else 0.0
        effort = 1e-3 * float(np.sum(np.square(action)))
        reward = approach + progress + touch + 0.5 * self.upright - effort
        return float(np.clip(reward, -10.0, 10.0))

    def is_terminated(self):                                  # fell over
        return self.base_height < 0.5 * self.initial_base_height or self.upright < 0.0

    def is_success(self):                                     # read when the episode ends
        return self._ball_to_goal() < 0.3 or self.objects_touch("ball", "goal")

Success only counts on a full episode

In MjcfRobotEnv, info["is_success"] is true only when the episode ended by reaching max_steps and is_success() holds. An episode that ends through is_terminated() is never a success, so do not terminate on success; let the robot hold the result until the time limit.

The Gymnasium wrapper route

Tasks on a built-in robot without objects usually wrap the Gymnasium model directly. The rules alia follows: create the robot with gym.make inside __init__ and never replace it, keep its action space, start from its observation space (appending task features is allowed if the space is widened), keep the base environment’s fall detection, truncate at max_steps, set info["is_success"], pass the seed through on reset and delegate rendering.

hop_at_speed.py · Gymnasium route
import numpy as np
import gymnasium as gym

ROBOT_ID = "Hopper-v5"


class HopAtSpeed(gym.Env):
    metadata = {"render_modes": ["rgb_array"], "render_fps": 125}

    def __init__(self, render_mode="rgb_array", max_steps=1000, target_speed=1.0):
        self._sim = gym.make(ROBOT_ID, render_mode=render_mode, max_episode_steps=max_steps)
        self.action_space = self._sim.action_space
        self.observation_space = self._sim.observation_space   # 11 proprioceptive values
        self.max_steps, self.target_speed = max_steps, target_speed

    def reset(self, seed=None, options=None):
        obs, _ = self._sim.reset(seed=seed)
        self._t = 0
        return obs, {"is_success": False}

    def step(self, action):
        action = np.clip(action, self.action_space.low, self.action_space.high)
        obs, _, terminated, truncated, info = self._sim.step(action)   # keeps Hopper's own fall check
        self._t += 1
        truncated = truncated or self._t >= self.max_steps
        speed_error = abs(info["x_velocity"] - self.target_speed)
        reward = info["reward_survive"] - speed_error + info["reward_ctrl"]
        info["is_success"] = bool(truncated and not terminated and speed_error < 0.2)
        return obs, float(reward), terminated, truncated, info

    def render(self):
        return self._sim.render()

    def close(self):
        self._sim.close()

What the task code may import is restricted; see the security scan. NumPy, Gymnasium, math and kualia_sim are what tasks normally need.

Build a task

World objects

Objects are real MuJoCo bodies declared in a SCENE list on the task class. The same list builds the world in the checks, in training and in the browser simulator. There are nine types.

SCENE
SCENE = [
    {"type": "ball", "name": "ball", "pos": [1.0, 0.0], "jitter": [0.2, 0.2]},
    {"type": "goal", "name": "goal", "pos": [4.0, 0.0]},
]
keep ≥ ~0.5 m clearrobot (0, 0)jitter ±0.2 mball (1, 0)goal (4, 0)1.2 m+x forward+y left
Top-down view of the example SCENE below (not to scale vertically). z points up, units are metres.

Types and defaults

TypeBehaviourDefaults (metres, kg)In the observation
ballmovableradius 0.11, mass 0.45position + velocity
boxmovablesize [0.15, 0.15, 0.15], mass 2.0position + velocity
stepfixedsize [0.4, 0.6, 0.08]not observed
rampfixedlength 1.5, width 1.0, height 0.2not observed
wallfixedsize [0.05, 1.0, 0.3]not observed
goalfixedwidth 1.2, height 0.6position
targetfixed, no collisionradius 0.25position
knobfixed base, cap turns on a vertical hingeradius 0.08, height 0.05, lever 0.12, damping 0.05position + angle + angular velocity
buttonfixed base, spring-loaded cap pushed downsize [0.08, 0.08, 0.03], travel 0.02, stiffness 60position + press position + velocity
  • Coordinates: x forward, y left, z up; the robot starts near the origin. pos is [x, y] (the object rests on the floor; its height is computed), within 20 m of the origin. A ball or box may also be given [x, y, z] to start higher.
  • Fixed pieces always stand on the floor. For step, ramp, wall, goal, target, knob and button a z is ignored, so nothing floats: make a taller step with a bigger size[2].
  • Sizes: size is half extents. Clamped ranges: radius 0.02–1.0, size 0.01–3.0, length/width/height 0.02–6.0, mass 0.01–50, lever 0–1.0, damping 0–10, travel 0.005–0.2, stiffness 0–2000.
  • Ramp rises along +x; its lower edge meets the floor at pos.x − length/2. Goal is two posts and a crossbar; its pos is the centre of the goal mouth. Target is a flat marker without collision, a place to reach.
  • Stairs are several steps in a row along +x, each one taller than the last: for example steps at x = 1.0, 1.4 and 1.8 m with size [0.2, 0.6, 0.05], [0.2, 0.6, 0.10] and [0.2, 0.6, 0.15] (10 cm risers, 40 cm treads).
  • Names must be unique (letters, digits, _); the helpers use them. At most 8 objects. Optional fields: rgba, observe (override whether it is observed), mass.
  • Numbers: plain numbers are simplest, but a SCENE may also use class-level numeric constants and simple arithmetic (STEP_W = 0.2, then "pos": [1.0 + 2 * STEP_W, 0.0]). kualia evaluates them safely from the source; nothing is executed.
  • Jitter [dx, dy] moves a movable object by a random offset at every reset, so the policy cannot memorise one position. Fixed objects ignore it.

Knobs and buttons

Two mechanisms are fixed in place and move in one degree of freedom, which makes them stand-ins for many everyday things:

  • knob: a fixed grey base with a cap that turns freely on a vertical hinge (no limit, light damping), plus a lever that gives a leg, arm or gripper something to push. A screw, bolt, valve, dial, crank or tap.
  • button: a spring-loaded, gravity-compensated push button. The cap rests fully up and only a push moves it down, by at most travel; the spring pushes it back. A switch, doorbell or key.
knobhinge (z)lever 0.12 mcap radius 0.08 m · fixed baseobject_angle · object_turnsbuttonpushtravel 0.02 mspring pushes it back up · pressed ≥ 60 %button_depth · button_pressed
Side views with the default sizes (not to scale). Both start at rest (angle 0, button up) at every reset.
turn_and_press.py · Panda
import numpy as np
from kualia_sim import MjcfRobotEnv, menagerie_asset


class TurnAndPress(MjcfRobotEnv):
    ROBOT_ASSET = menagerie_asset("Panda")   # Franka arm + gripper, starts in its "home" pose
    CONTROL_HZ = 50
    SCENE = [
        {"type": "knob", "name": "valve", "pos": [0.5, -0.15], "radius": 0.04},
        {"type": "button", "name": "bell", "pos": [0.5, 0.15], "size": [0.04, 0.04, 0.015]},
    ]

    def on_reset(self):
        self.prev_turns = 0.0

    def compute_reward(self, action):
        turns = self.object_turns("valve")                    # signed full turns this episode
        progress = 5.0 * (self.prev_turns - turns)            # clockwise (negative angle) is progress
        self.prev_turns = turns
        pressed = 1.0 if turns <= -1.0 and self.button_pressed("bell") else 0.0
        effort = 1e-3 * float(np.sum(np.square(action)))
        return float(np.clip(progress + pressed - effort, -10.0, 10.0))

    def is_success(self):                                     # one full turn, then ring the bell
        return self.object_turns("valve") <= -1.0 and self.button_pressed("bell")

Reading the world in the hooks

HelperReturns
object_position("ball")world position [x, y, z]
object_velocity("ball")linear velocity [vx, vy, vz] (zeros for fixed objects)
object_offset("ball")object position minus robot base position
object_distance("ball")horizontal distance between robot base and object
robot_touches("ball")True while any robot part touches the object
objects_touch("ball", "goal")True while the two objects touch
object_initial_position("ball")where it was placed this episode (after jitter)
object_angle("knob")knob angle in radians, 0 at reset, unbounded (2π per full turn)
object_angular_velocity("knob")knob angular velocity, rad/s
object_turns("knob")signed full turns since the start of the episode
button_depth("button")how far the button is pressed, 0 … travel metres
button_pressed("button")True while pressed at least 60 % of its travel

The knob helpers only accept a knob and the button helpers only a button; calling them on another type raises an error.

Objects in the observation

Observed objects are appended to the policy’s observation automatically, in SCENE order: the object’s position relative to the robot base (3 values), plus its velocity for movable objects (3 values, clipped to ±20 m/s). A knob adds its angle and angular velocity, a button its slide position (negative while pressed) and velocity (1 value each). In the example, the ball adds 6 values and the goal 3; a knob or a button adds 5. The task must not add them again in extra_observation, and leaving extra_observation undefined keeps the policy runnable live in the browser.

The “Objects start clear” check

After three resets, objects must not start inside the robot (more than 5 mm deep), inside each other, below the floor, or right under the robot (a ball or box within 0.15 m of the base horizontally). A 60-step random rollout must keep every object physically sane (no speeds above 60 m/s, not falling through the floor). The check also fails when the task’s SCENE lacks an object type the world planner decided on (stored with the spec; for older tasks, the objects named in the brief). Keeping objects clear of the start pose, within the robot’s placement range below, avoids almost all failures.

Where objects go, per robot

Objects are only useful where the robot can reach them. alia and the world planner are given this guidance for each robot:

RobotPlacement
InvertedPendulumA cart on a rail; it cannot touch the floor. Objects are rarely useful, prefer none.
ReacherFixed base at the origin; the fingertip reaches 0.08–0.21 m and moves about 1 cm above the floor. Objects within 0.1–0.2 m of the origin and low (e.g. knob radius 0.03, height 0.02).
Hopper, Walker2dPlanar: objects on the line y = 0, 0.8–3 m ahead. Low steps (risers ≤ 0.1 m; Walker2d treads ≥ 0.4 m).
HalfCheetahPlanar: objects on y = 0, 1–4 m ahead. Obstacles lower than ~0.2 m can be jumped.
AntMoves in any direction. Objects 1–3 m away; buttons and knobs are pressed or turned with a leg.
HumanoidStairs: risers ≤ 0.1 m, treads ≥ 0.4 m, first step ≥ 0.8 m ahead. Objects to kick or push 1–2 m ahead.
Go2Objects 0.8–3 m away; risers ≤ 0.08 m; a ball to push ~0.1 m radius.
SpotObjects 1–3 m away; risers ≤ 0.15 m.
OP3Objects 0.3–1.5 m ahead; steps ≤ 0.03 m high; a ball to kick ~0.05 m radius.
G1Objects 1–2 m ahead; stair risers ≤ 0.1 m.
PandaFixed base; the hand reaches about 0.3–0.8 m. Objects 0.4–0.6 m in front and within ±0.3 m sideways, small (box size ≤ 0.03, knob radius 0.04, button size [0.04, 0.04, 0.015]).

Inspect the world before training

The World panel on Plan & world renders the exact composed scene. Press play for a zero-torque drop test: objects that jump or fly away are overlapping something at the start.

Build a task

Rewards

The reward is the only thing the policy optimises. It is computed at every control step, and training maximises its sum over an episode.

Dense shaping vs goal-based

Dense shaping (the default) pays for progress every step: velocity toward a target, distance closed to a ball, height gained. The robot gets a useful signal from its very first attempts, which is why it learns faster. Goal-based gives a clear bonus for completing the goal plus light shaping; the behaviour is cleaner but learning is slower, because the bonus is rare early on.

A reward is normally a weighted sum of terms. An illustrative locomotion reward (your task’s terms and weights will differ):

TermWeightMeaning
forward velocity1.0metres per second along +x
upright0.51 when upright, less when tilted
control cost−0.001sum of squared actions (smooth, efficient motion)
fall penalty−10once, when the episode terminates by falling

Explain the reward on Plan & world lists the terms from the training plan. Weights, and the donut of their absolute sizes, are shown only when the plan states numeric weights; otherwise the exact scaling lives in the task code (open Generated task code).

How rewards are scaled during training

Training normalises rewards with a running estimate (and clips normalised values to ±10), so absolute scale matters less than the balance between terms. Per-step rewards should still stay roughly within [−10, 10]; the Reward is sane check warns when random actions produce values outside that range. The charts always show the raw episode return, in the task’s own units.

Common pitfalls

SymptomLikely causeFix
The robot stands still, reward looks fineA survival / alive bonus that outweighs the progress terms: standing still collects it risk-free.Lower the bonus or make it conditional on progress; raise the progress weight.
The robot falls on purposeNet negative reward per step (penalties larger than rewards), so ending the episode early is optimal.Make a normal, upright step slightly positive; keep penalties smaller.
Learnability check failsThe reward does not depend on anything the actions change.Reward robot or object state that the actions influence.
Reward is sane check failsNaN/inf (division by a quantity that can be zero) or a constant reward.Guard divisions, clip velocities, make terms vary.
The ball flies sidewaysRewarding object speed in any direction (reward hacking).Reward progress toward the goal instead, as in the task example.
No progress in a short runGoal-based reward on a hard trick: the bonus is never seen.Switch to dense shaping or add a curriculum stage.

Tip

When a run disappoints, the AI analysis on the run’s results page reads the curve, the evaluation episodes and the code, and proposes concrete reward changes with current and proposed values.

Build a task

Success & termination

An episode ends in one of two ways, and the difference matters for learning and for the success rate.

MeaningExamples
terminatedThe episode failed or hit a hard stop.Fell over, flipped, left the allowed area.
truncatedTime ran out: max_steps control steps were reached.The robot kept going until the episode length.

Episode length (max_steps) is a task parameter; the checks measure the cap the code actually enforces and the Studio shows it on the Training screen (“steps / episode”). The default termination in the kualia_sim runtime ends the episode when a floating robot’s base drops below half its start height or turns upside down. Built-in robots on the Gymnasium route keep the base environment’s own fall detection (for example Hopper ends when the torso is too low or tilts too far).

The success criterion

Success is reported in info["is_success"] and is meaningful at the end of an episode. It drives the success rate on the Training chart (share of the last 50 training episodes) and in the results (share of the evaluation episodes).

  • In the kualia_sim runtime, success requires reaching the time limit without terminating, and is_success() returning true at that moment.
  • If a task never sets is_success, kualia counts an episode with a positive total reward as a success. Treat the success rate of such a task with care, and ask alia to implement an explicit criterion.

Every threshold must hold at the reset pose

The most common broken task ends every episode at step one: a termination test on a quantity that is zero or out of range at the start. On Hopper and Walker2d, z_distance_from_origin is relative (≈ 0 at reset), not a height; on HalfCheetah the first observation value is a z offset, not a height. The Episodes survive the reset check catches this before training.

Build a task

Observations & actions

Observations are what the policy sees every step; actions are what it sends to the actuators.

Observations

kualia_sim tasks (every task on a realistic or uploaded robot, and classic-robot tasks with objects) observe the robot’s joint positions (dropping the world x/y of a floating or planar base, so the policy does not depend on where it is on the floor), the joint velocities, then every observed object, then the optional extra_observation() values. A ball or box adds its relative position and velocity (6 values), a goal or target its relative position (3), a knob its relative position, angle and angular velocity (5), a button its relative position, slide position and velocity (5).

  • qposjoint positions (world x/y of the base dropped)
  • qveljoint velocities, clipped to ±50
  • ballrel. position 3 + velocity 3
  • goalrel. position 3
  • extraextra_observation()
Observation layout of a kualia_sim task with a ball and a goal (widths not to scale).

Gymnasium-route tasks start from the robot’s own observation (the Obs column in the robot table) and may append task features such as a target speed or a phase, widening the space accordingly.

The Plan page lists the observation signals from the training plan, including the objects (“position relative to the robot + velocity”). The Observations tab of the World panel shows live base values during the drop test: height, roll / pitch / yaw and velocity.

During training observations are normalised with a running mean and standard deviation (clipped to ±10). That normalisation is exported inside the ONNX file, so on the robot you feed raw values in the same order.

Actions

The action is one continuous value per actuator. In the kualia_sim runtime every actuator is normalised to [−1, 1] and mapped linearly onto its control range: −1 is the low end, +1 the high end. For position servos that is a joint target, for motors a torque. Gymnasium-route tasks use the robot’s own action space. Actions outside the bounds are clipped.

Robots that ship a standing keyframe (the realistic robots, and uploaded models with a keyframe) start every episode from it, and each position actuator’s range is shifted so that its centre is the keyframe’s command (the width stays the same). A zero action therefore holds the standing pose, and the policy learns offsets from it.

action → actuator (kualia_sim)
ctrl = ctrl_low + 0.5 * (action + 1.0) * (ctrl_high - ctrl_low)   # action in [-1, 1]

Build a task

Automated checks

Every task version runs 13 checks in an isolated sandbox. Training starts only when all 13 pass, so training steps are never spent on a task that breaks at step one.

#CheckGroupWhat it tests
1Code parses
syntax
setupThe file parses as Python. If it does not, every other check is skipped.
2Security scan
security
setupStatic scan before anything runs: blocked modules, eval / exec / compile / __import__, and .system / .popen / .spawn / .fork calls. A violation skips the runtime checks.
3Environment loads
import
setupFinds the environment class (the most-derived gymnasium.Env in the file), instantiates it and confirms it has an observation and an action space.
4Reset works
reset
setupreset(seed=42) returns a tuple (observation as a NumPy array, info dict).
5Step works
step
setupOne random action returns the five-tuple (obs, reward, terminated, truncated, info) with the right types.
6Observation signals
obs_space
physicsThe first observation and ten more after random steps all lie inside the declared observation space.
7Action space valid
action_space
physics100 sampled actions lie inside the action space, and stepping with one works.
8Reward is sane
reward_sanity
learning100 random steps give numeric, finite rewards that are not all identical. Values outside [−10, 10] produce a warning.
9Deterministic reset
determinism
physicsTwo 20-step rollouts with the same seed (and the same action seed) give identical observations and rewards.
10Learnability estimate
action_effect
learningLearnability estimate: over five seeds, the 50-step return with random actions must differ from the return with zero actions. If actions cannot change the return, nothing can be learned.
11No unstable physics
stability
physicsThree rollouts of up to 300 steps, one with saturated bang-bang actions: finite observations and rewards, observations inside finite declared bounds, no explosion (|obs| ≤ 1e6), and episodes that actually end.
12Episodes survive reset
episode_length
learningFive random-action episodes (up to 300 steps) must last more than two steps on average. Also reports the episode cap the code enforces.
13Objects start clear
scene
physicsWorld objects start clear of the robot and of each other, above the floor, stay physically sane for 60 random steps, and every object type the world planner decided on exists in SCENE. Passes on an open floor.
  • Runtime checks run in parallel, each in a separate subprocess with a 20-second limit and with server secrets removed from its environment.
  • Blocked modules: subprocess socket socketserver asyncio multiprocessing requests httpx urllib urllib2 urllib3 http ftplib smtplib telnetlib paramiko pickle cpickle marshal shelve ctypes cffi pty shutil pathlib glob sqlite3 importlib imp runpy webbrowser signal resource fcntl.
  • Failing checks are repaired automatically: up to four attempts when the plan is first built, up to three after every chat change, always keeping the best-scoring code.
  • On Plan & world, click a check to read its detail message, Re-run to run them again, and Ask assistant to fix to send any remaining failures to alia. The Training readiness ring summarises them.

Passing checks do not guarantee learning

The checks prove the task is well-formed, stable and learnable in principle. Whether the reward describes the behaviour you want is something only training, the recordings and the analysis can tell you.

Train & iterate

Training

Training runs on kualia’s servers with PPO (Proximal Policy Optimization) from Stable-Baselines3. You choose how many steps the robot practises; everything else is set up for you.

What happens in a run

  • Algorithm: PPO with a multilayer-perceptron policy and Stable-Baselines3’s default hyperparameters. The Studio always trains with PPO.
  • Normalisation: observations and rewards are normalised with running statistics (clipped to ±10). The chart and the evaluation still report raw rewards.
  • Checkpoints: the untrained policy is recorded first, then at 25, 50 and 75 % of the budget, then the final policy.
  • Evaluation: after training, the final policy plays 5 episodes deterministically (seeds 0–4, frozen normalisation). These are the numbers on the results page.
  • Queue: when the training servers are busy the run shows Queued and starts automatically.
  1. 0 %untrained policy recorded
  2. 25 %first live checkpoint policy
  3. 50 %checkpoint
  4. 75 %checkpoint
  5. finalmodel saved · up to 30 evaluation episodes
Every checkpoint records one deterministic episode as a video and as a MuJoCo trajectory for the 3D replay.

Practice budgets

The Plan page, the Training page and Train again, as it is offer three budgets, each with its price and a time estimate (based on the throughput of this task’s earlier runs when there are any):

BudgetStepsUse it to
First try10KCheck that the robot moves sensibly and episodes do not end at once.
More practice50KSee early behaviour; enough for the easiest robots.
Learn itrobot-specificA typical budget to actually learn a skill on this robot.
FamilyLearn it budget per robot
ClassicInvertedPendulum 30K · Reacher 100K · Hopper 300K · HalfCheetah 300K · Walker2d 500K · Ant 1M · Humanoid 2M
RealisticPanda 500K · Go2 3M · Spot 3M · OP3 5M · G1 10M
Uploaded300K

These are rough orders of magnitude, not guarantees; steps come out of your plan’s monthly quota (Starter 300K, Pro 1M; see Plans & training steps), and a single run is capped per plan (Free 20K, Starter 500K, Pro 2M); Keep training continues a policy across several runs.

The Training screen

  • Live simulation: a 3D replay of the latest checkpoint, the recorded video, the physics drop test, and the live policy (see below).
  • Recent attempts: the checkpoints as a film strip. Each tile shows Full episode or Ended at n / max and the episode reward; the best one is outlined.
  • Learning progress: average episode reward with a min/max band, plus success rate, episodes, elapsed and remaining time and throughput. A point is added about every 5 % of the run, averaged over the last 50 training episodes. The phase bar (Warm-up → Exploration → Stabilization → Convergence) simply tracks progress through the budget.
  • Training log: readable events derived from the curve and checkpoints (reward improved, success rate reached, episodes last longer, most episodes still end early, checkpoint recorded).
  • Run statistics: best and latest checkpoint reward, average episode length, early ends in evaluation, throughput and the previous best run.

Why the checkpoint reward is higher than the chart

Training episodes are played by the exploring policy, which adds random noise to every action; that is how PPO discovers better behaviour. Checkpoints and evaluation use the deterministic policy (its best guess, no noise), so their reward is usually higher than the average on the chart.

Live policy during training

From the 25 % checkpoint on, the newest checkpoint policy is saved while training continues and exported to ONNX on request (GET /api/rlforge/train/{env_id}/onnx/live?run_id=…). In Live policy mode the simulator loads it and runs it in your browser; it refreshes as new checkpoints are recorded. This only works for tasks that the browser can simulate (see Browser simulator).

Stop, train again, keep training

  • Stop training ends the process. A stopped run is not refunded.
  • Train v<n> again starts a fresh policy on the same version with the same budget, useful to see how much results vary between runs.
  • Keep training continues from the model of the most recent completed run and adds at least 50K steps. If that model cannot be loaded (for example the observation size changed in a later version), a fresh policy is trained instead.

Why short runs don’t teach complex robots

PPO learns from experience: each update uses a batch of steps, and a skill emerges over many updates. On InvertedPendulum 10K steps already shows progress. On Humanoid (17 actuators, a 348-value observation, an unstable body) 10K steps is only a few batches, and the policy is still close to random; a skill typically needs around 2M steps. The realistic robots are harder still: a first gait on Go2 or Spot is in the millions of steps, and G1 with 29 joints in the order of 10M. A short run on a big robot is still worth it: it shows whether episodes survive, whether the reward rises and whether the robot is heading the right way, before you pay for a long run.

Train & iterate

Results & iteration

Training is a loop: run, look, change one thing, run again. The Results stage keeps every run of every version side by side.

Runs & versions

  • Design a new run drafts a message to alia for the next version: change the world, the reward, or how an episode starts and ends. If the last run was analysed, Apply the AI suggestions sends its instruction directly.
  • Train again, as it is trains the current version with a chosen budget, or keeps training from its best run.
  • The run list can be filtered by version and status and sorted by newest or best reward. Versions that were never trained appear too, with Review & train (current) or Make current.
  • Compare: tick two completed runs to overlay their reward, success rate and episode length curves.

One run’s results

PanelWhat it shows
Best policy rolloutThe run’s policy in the simulator, live in the browser when the task supports it, otherwise the 3D replay or the video.
Evaluation performanceAverage reward and success rate over training.
Evaluation episodesUp to 30 deterministic episodes (seeds 0–29; after the first 10, evaluation stops at a 90-second budget): success count with a 95% Wilson interval, one square per episode, then reward, length and outcome (success, no success or ended early) for each.
Best checkpointThe highest-reward checkpoint with its step, reward and length.
Failure casesEvaluation episodes that ended early, plus the analysis’ observations with a severity (low / medium / high).
Result summarySuccess rate, mean reward, episode length, early ends, episodes trained, training time, each compared with the previous run.
ActionsCompare with other runs, export the policy, train again or keep training, create the next version from the analysis.

The AI analysis

The first time you open a run’s results, an analysis runs automatically and is stored with the run, so later visits cost nothing. It reads the training curve, the evaluation numbers, the recorded episodes and the task code, and returns:

  • a 2–3 sentence summary of what the robot does and the main problem,
  • 2–4 observations with severity,
  • 3–6 proposed changes, each tagged reward, termination, observation, curriculum or hyperparameters, with the current and proposed value and why,
  • an optional curriculum and a ready-to-send instruction for alia.

Re-analyze runs it again (the button shows the estimated cost). Create v<n> from the analysis sends the instruction to alia, which creates the next version and re-runs the checks.

Rolling back

Make current restores an older version’s task code and plan and re-runs its checks. Runs are never deleted by a rollback, and a later change is saved under the next free version number.

A useful rhythm

  1. 10K-step run: does the behaviour point the right way?
  2. Read failure cases and the analysis; change one thing.
  3. Compare the two runs; keep the better version current.
  4. When the direction is right, spend the Learn it budget or keep training.

Train & iterate

The browser simulator

The Studio runs MuJoCo compiled to WebAssembly in your browser, so you can inspect the world and watch policies without downloading anything.

Modes

ModeWhat drives the robot
Live policy (in-browser)The exported ONNX policy, evaluated with onnxruntime-web, acting in MuJoCo in real time. The status line shows episode, step, time, falls and inference time per step; episodes restart after a fall or at the end.
3D replay (MuJoCo)The recorded state of a checkpoint’s evaluation episode, played back in 3D.
Recorded videoThe MP4 rendered on the server for that checkpoint.
Physics drop testZero torque: the robot and the world simply fall under gravity. Good for spotting objects that overlap at the start.

It appears on Plan & world (the World panel, starting in drop-test mode), on Training, on each run’s results (starting in live-policy mode) and on Export (the exact ONNX file you download). The realistic robots are loaded with all their mesh files, so the first view of one takes a moment longer; they start in their standing pose, as in training.

Controls

  • Drag to orbit, scroll to zoom; Follow robot keeps the camera on it, Recenter resets the view.
  • Play / Pause, playback speed 0.25×–2×, Reset.
  • Push shoves the robot sideways for 0.15 s: a quick robustness test for a live policy.
  • In video mode: play, pause, reset and fullscreen.

Requirements

The simulator needs SharedArrayBuffer, which browsers only provide on cross-origin-isolated pages; kualia serves its app pages with the required headers. Use a current Chrome, Edge or Firefox. Where isolation is unavailable the simulator shows “3D simulator unavailable” and the recorded video still works.

When live policy is not available

To run a policy in the browser, kualia must rebuild the exact observation the task fed the policy in training. It derives a declarative recipe from the task, checks it step by step against the real environment on the server, and ships it only if they agree. Supported:

  • kualia_sim tasks that do not add extra_observation() features (world objects are included);
  • Gymnasium-route tasks that pass the robot’s observation through unchanged, apply actions directly and keep the robot’s control period.

Custom Python observation features, action remapping or a different control period make the task unsupported; the viewer then says “Live policy off for this task” with the reason and shows the recorded rollout. The Export page lists the same result under Browser simulation.

Deploy & account

Export & deployment

Export turns the best run of a task into a single ONNX file that runs anywhere onnxruntime runs, from a laptop to a Raspberry Pi or Jetson.

What you get

  • The best completed run (highest mean return) is exported. The file is named <task>_run<id>_PPO.onnx.
  • ONNX opset 17, input obs, output action, dynamic batch dimension.
  • The deterministic policy: for PPO, the mean action, exactly what model.predict(obs, deterministic=True) returns in Stable-Baselines3.
  • Observation normalisation baked in as the first layer (training mean and standard deviation, clip ±10). Feed raw values.
  • Actions are clipped to the action-space bounds inside the graph.
  • Verified: the model passes the ONNX checker and is compared with the original policy on 16 random observations; an export that differs by more than 0.001 is rejected.
  • Metadata is embedded in the ONNX file (metadata_props) and saved as JSON next to it; the Export page shows it, with the file size and SHA-256 checksum.
Inside the exported .onnx file (orange: part of the graph). No PyTorch or Stable-Baselines3 is needed on the robot.
policy metadata (example values)
{
  "format": "onnx",
  "opset": 17,
  "algorithm": "PPO",
  "deterministic": true,
  "input":  { "name": "obs", "dtype": "float32", "shape": [1, 23],
              "note": "RAW environment observation; normalisation is baked into the graph" },
  "output": { "name": "action", "dtype": "float32", "shape": [1, 6],
              "note": "clipped to action space bounds" },
  "action_space": { "type": "Box", "low": [-1, ...], "high": [1, ...] },
  "obs_normalization": "vecnormalize",
  "obs_clip": 10.0,
  "robot_model": "Walker2d", "env_id": 12, "env_slug": "kick-the-ball", "env_version": 3, "run_id": 42,
  "exported_by": "kualia.ai",
  "verified": true, "max_abs_diff_vs_sb3": 2.4e-07,
  "size_bytes": 41213, "sha256": "…",
  "browser_sim": { "supported": true, "recipe": { … } }
}

The Export page

  • Try the exported policy: the same ONNX file, running live in the browser simulator. Push the robot to test robustness.
  • Export summary: input observation schema, output joint command schema, normalisation, runtime target, control rate, package name and version (task version · run id).
  • Deployment handoff: export completed, model validated, normalisation embedded, browser simulation supported, artifact packaged, plus the integrity hash.
  • Download File, Copy Runtime Instructions and a minimal runtime snippet.

Running it on the robot

robot_loop.py
# On the robot: only onnxruntime + numpy (pip install onnxruntime numpy)
import json, time
import numpy as np
import onnxruntime as ort

sess = ort.InferenceSession("kick_the_ball_run42_PPO.onnx", providers=["CPUExecutionProvider"])
meta = {k: json.loads(v) for k, v in sess.get_modelmeta().custom_metadata_map.items()}
obs_dim = meta["input"]["shape"][1]


def act(obs):
    x = np.asarray(obs, dtype=np.float32).reshape(1, obs_dim)   # RAW values, training order
    return sess.run(["action"], {"obs": x})[0][0]                # normalisation happens inside


HZ = 125   # the task's control rate, shown on the Export page
while True:
    t0 = time.perf_counter()
    a = act(read_sensors())       # your code: build the observation vector
    send_joint_commands(a)        # your code: map each value in [-1, 1] onto the actuator range
    time.sleep(max(0.0, 1.0 / HZ - (time.perf_counter() - t0)))

For kualia_sim tasks, each action value maps onto the actuator’s control range as low + 0.5 · (a + 1) · (high − low), the same as in simulation (for a position servo, a joint target). The action_space entry in the metadata gives the bounds of the policy output. On the realistic robots (and uploaded models with a keyframe) each position actuator’s range is centred on the standing keyframe, so a zero action holds the standing pose; use those same shifted ranges on the robot. When the task supports browser simulation, the metadata’s browser_sim recipe lists them exactly (ctrl.low, ctrl.high).

Sim-to-real

A policy trained in simulation can behave differently on hardware: motor latency, friction, battery voltage. Start at low gains and speeds and keep an emergency stop within reach. Match the observation layout exactly (joint order, radians and rad/s, the base-pose convention used in simulation). If the robot’s control loop runs at a different rate, retrain with CONTROL_HZ set to the real rate rather than resampling actions. Your runtime must support ONNX opset 17 (onnxruntime 1.16 or newer).

Direct push to a robot runtime is on the roadmap; today the handoff is the ONNX file.

Deploy & account

Plans & training steps

A plan is two numbers: how many training steps your robot gets every month, and alia, the assistant that builds and edits tasks. Steps are counted per run and taken from your monthly quota when the run starts; there is nothing else to pay per run.

PlanPriceTraining steps / monthaliaTrainings at a timeWorld DesignerStep packs
Free$020K once, to try it (1 project)builds your first task1nono
Starter$20 / month300Kincluded1nono
Pro$50 / month1Mincluded3yes250K for $10 · 500K for $20
LabLet's talksized to your lab + GPU trainingincluded6yesyes

When the steps run out, a run is refused with a clear message: Starter moves up to Pro, Pro adds a step pack (as often as needed; packs never expire). alia has a monthly allowance inside each plan; if a month is unusually heavy it pauses until the plan renews, and your work is saved.

BudgetSteps
First try10K
More practice50K
Learn it · InvertedPendulum30K
Learn it · Reacher100K
Learn it · Hopper300K
Learn it · Walker2d500K
Learn it · HalfCheetah300K
Learn it · Ant1M
Learn it · Humanoid2M
Learn it · Dynamixel2R50K
Learn it · LowCostArm200K
Learn it · SO101300K
Learn it · Crazyflie300K
Learn it · Duck2M
Learn it · Toddlerbot5M
Learn it · OP35M
Learn it · Panda500K
Learn it · Go23M
Learn it · Spot3M
Learn it · G110M

Refunds

  • A run that fails with an error gives its steps back automatically; the run statistics show it.
  • A run you stop keeps its steps spent, and so does a run that completes but does not learn the trick.

See Pricing for the plan comparison. Buy step packs or change plan under Settings → Plan & steps.

Deploy & account

API reference

The Studio is built on a REST API. These are the endpoints it uses, for reference.

Authorisation

Send a personal API key (Authorization: Bearer kua_…, created under Settings → API keys) or your signed-in session token. Keys act as you — credits and plan limits apply — and never reach admin features. Endpoints may still evolve; the MCP server is the stable way for agents to drive kualia.
MethodPathPurpose
GET/api/rlforge/robotsBuilt-in robots and your uploads
POST/api/rlforge/robots/uploadUpload and validate a robot model
POST/api/rlforge/generateBuild a plan: { description, difficulty, robot_model }
GET/api/rlforge/envs/{env_id}A task: code, plan, checks, world
GET/api/rlforge/envs/{env_id}/scene.xmlThe composed world as MJCF
POST/api/rlforge/envs/{env_id}/validateRun the 13 checks again
GET/api/rlforge/envs/{env_id}/versionsTask versions with change summaries
POST/api/rlforge/builder/{env_id}/chatAssistant message: { message }
GET/api/rlforge/builder/{env_id}/historyAssistant conversation
POST/api/rlforge/builder/{env_id}/rollbackMake a version current: { version }
POST/api/rlforge/builder/{env_id}/analyzeAI analysis of the latest completed run
GET/api/rlforge/pricingCurrent prices and estimates
POST/api/rlforge/generateBuild a task: { description, robot_model, difficulty, async: true } → { id, status: "generating" }
POST/api/rlforge/train/{env_id}Start a run: { total_timesteps, algorithm, continue_from }
GET/api/rlforge/train/{env_id}/statusLatest run status
GET/api/rlforge/train/{env_id}/curveTraining curve of the latest run
GET/api/rlforge/train/{env_id}/report/{run_id}Curve and results of one run
POST/api/rlforge/train/run/{run_id}/stopStop a running or queued run
GET/api/rlforge/train/{env_id}/onnx?run_id=Download the ONNX policy
GET/api/rlforge/train/{env_id}/onnx/meta?run_id=Policy metadata
GET/api/rlforge/train/{env_id}/onnx/live?run_id=Newest checkpoint policy of a running run

Starting a run returns 409 checks_failing when not all checks pass, 402 steps_exhausted when your plan has fewer training steps left than the run needs, 409 too_many_runs above your plan’s parallel runs and 403 plan_limit_exceeded above its steps per run. AI calls return 402 insufficient_credits when the plan’s monthly assistant allowance is used up.

Deploy & account

Coding agents (MCP)

Claude Code, Cursor, Codex and any other MCP client can drive kualia: pick a robot, build the task, train it and fetch the ONNX policy — without leaving your editor.

kualia is a remote MCP server (Streamable HTTP) at https://kualia.ai/api/mcp. Create a personal API key under Settings → API keys and add the server to your agent:

Claude Code
claude mcp add --transport http kualia https://kualia.ai/api/mcp \
  --header "Authorization: Bearer $KUALIA_API_KEY"
Cursor — .cursor/mcp.json (Windsurf and others are similar)
{
  "mcpServers": {
    "kualia": {
      "url": "https://kualia.ai/api/mcp",
      "headers": {
        "Authorization": "Bearer kua_…"
      }
    }
  }
}
Codex — ~/.codex/config.toml
[mcp_servers.kualia]
url = "https://kualia.ai/api/mcp"
http_headers = { Authorization = "Bearer kua_…" }

Tools

ToolWhat it does
list_robotsBuilt-in robots (tiny, classic, realistic) and your uploaded ones
create_taskrobot + trick (+ optional success, difficulty) → a task built in the background; returns task_id
get_taskStatus, plan (trick, success scenario, world objects, reward), check results, Studio link
start_trainingtask_id + steps (10,000 for a first try) → a PPO run
get_trainingLatest run: status, progress, mean reward, success rate
get_policyONNX and metadata download URLs for the latest completed run

Then just ask, for example: “Train my SO-101 to press a button with kualia, start with a 10K-step try and tell me the success rate.” The agent builds the task, waits for the checks, starts training and reports back; the Studio link lets you watch the robot and change the task with alia.

For agents reading this page

A machine-readable summary lives at /llms.txt and the full reference at /llms-full.txt.

Help

Troubleshooting

The problems people hit most, and what to do about them.

“Episodes survive the reset” fails

Random-action episodes last two steps or fewer, so a termination (or success) condition already fires at the start pose. Typical causes: a height test on a relative quantity (z_distance_from_origin is ≈ 0 at reset), a threshold stricter than the start pose (a “stay above 1.3 m” test on a robot that starts at 1.25 m), a HalfCheetah task treating its first observation value as a height, or terminating on success. Click Ask assistant to fix; the check’s detail message tells it what went wrong.

“Learnability estimate” fails

Random and zero actions produce the same return: the reward does not depend on anything the robot’s actions change (a constant bonus only, or a term reading the wrong variable). Ask for a reward on robot or object state, such as forward velocity or distance to the target.

“Objects start clear” fails

An object starts inside the robot, inside another object, below the floor or right under the robot, behaves unphysically in the first 60 steps, or the SCENE lacks an object type the world planner decided on. Move objects clear of the start pose (see where objects go for your robot), reduce jitter, or ask alia to add the missing object. Chat changes already run up to three automatic fixes; if the check still fails, Ask assistant to fix sends the details.

The world has objects I didn’t want (or lacks one I did)

The world planner re-plans on every chat change, so say it plainly: “no objects, just walk forward”, “add a button 0.5 m in front”, “use two steps instead of three”. The note under Your trick on the Plan page shows how it read your words, including anything it could not simulate.

Other failing checks

CheckUsual cause
Security scanAn import of a blocked module (os-level, network, pickle, importlib…) or eval/exec.
Reward is saneNaN or infinite rewards (division by zero, exploding velocities) or a constant reward.
Deterministic resetRandomness from np.random instead of self.np_random, or the seed not passed to the robot’s reset.
Observation signalsAn observation outside the declared space, often after appending features without widening the space.
No unstable physicsNon-finite or exploding observations under saturated actions, or episodes that never end within 300 steps.

“3D simulator unavailable”

The page is not cross-origin isolated, so SharedArrayBuffer is missing: often Safari, an in-app browser, or an extension that rewrites headers. Open the page in current Chrome, Edge or Firefox. Recorded videos keep working either way.

“Live policy off for this task”

The browser cannot rebuild this task’s observation, usually because it adds features in extra_observation(), remaps actions or changes the control period. The hover text gives the exact reason. Use 3D replay or video, or ask alia to express the extra features as SCENE objects (observed automatically). During training, live policy becomes available once the 25 % checkpoint exists.

The robot doesn’t learn

What you seeWhat it usually means
Flat reward, episodes a few steps longThe robot fails the termination at once. Check the failure conditions and the drop test; soften thresholds or start on Easy.
Reward rises, success stays at 0 %The reward and the success criterion disagree. Align them, or loosen the criterion in a new version.
High reward, the robot barely movesA survival bonus dominates; see the reward pitfalls.
Everything looks right but slowNot enough steps. Compare with the robot’s Learn it budget and keep training.
Behaviour exploits the rewardThe reward pays for a shortcut (spinning, flinging an object). Reward the actual result.

Open the run’s results: the failure cases and the AI analysis usually name the problem, and the proposed changes turn into the next version with one click.

Training won’t start or failed

  • Start is disabled or refused: some checks still fail, the balance is below the run price, or the budget exceeds your plan’s steps per run.
  • Keep training is disabled: the current version has no completed run yet.
  • The run failed: the task raised an error during training; its training steps are returned automatically. Ask alia about the error and train the fixed version.

An uploaded robot “needs validation”

The validation report found an error: no actuators, a non-finite or exploding state in the rollouts, or a model MuJoCo could not load (often a missing mesh or an absolute path). Open the report on the Robots page, fix the model and upload it again.

Help

FAQ

Do I need to write code?+
No. alia writes and changes the task; you describe what you want. The code is shown on the Plan page so you can read and copy it.
Can I edit the task code by hand?+
Changes go through alia, which keeps every edit versioned and re-runs the checks. Paste the exact change you want into the chat if you know it.
Which RL algorithm is used?+
PPO from Stable-Baselines3 with default hyperparameters. Continuing a run keeps the same algorithm.
Do I need a GPU?+
No. Training runs on kualia’s servers, and the browser simulator runs on your CPU.
Is the world in training the same as in the browser?+
Yes. The task’s SCENE is read from the code and composed onto the robot model in the checks, in training and in the simulator.
What happens to my runs when I roll back?+
Nothing. Runs stay pinned to the version they trained on; a rollback only changes which version is current.
Can I use the policy on a real robot?+
Yes, via the ONNX export and onnxruntime. Mind the sim-to-real notes in Export & deployment: match the observation layout and the control rate.
Why does the success rate differ between the chart and the results?+
The chart averages the last 50 exploring training episodes; the results use up to 30 deterministic evaluation episodes, with a 95% interval on the success rate.
Can a trick use several objects?+
Yes, up to 8 per world, of any mix of the nine types: ball, box, step, ramp, wall, goal, target, knob and button.
Which robots are realistic, and which are classics?+
Go2, Spot, OP3, G1 and Panda are models of real robots from MuJoCo Menagerie; they start standing and need millions of steps for a gait. The seven Gymnasium robots (InvertedPendulum to Humanoid) are simplified classics that train fast. See Robots.
Can the robot turn a screw or press a button?+
Yes, in simulation: a screw, valve or dial becomes a knob and a switch or doorbell a button. Rewards and success can use object_turns and button_pressed. Panda is the natural robot for it; legged robots press and turn with a leg.
Can I describe the trick in another language?+
Yes. The world planner reads the meaning in any language (for example Turkish “merdiven” is stairs, “zil” a doorbell) and alia writes the task from it.
What are the licenses of the realistic robot models?+
They are MuJoCo Menagerie models, each under its own license: Go2, G1 and Spot BSD-3-Clause, OP3 and Panda Apache-2.0. kualia pins them to one Menagerie commit and keeps their license files.

Ready to teach a trick?

Start with InvertedPendulum or Reacher and a 10K-step run.

Open the Studio