Robots and Tasks
A robot is a URDF in your workspace. The trajectory views draw episodes on it, and the reach solver walks handheld takes onto its arms. Neither works without the robot’s URDF.
A Task describes what the robot does and what success and failure look like. A model reads this text and your reference takes to draft the steps and check every uploaded episode against the Task, so these words decide what gets flagged.
A Task is a draft you edit, published as numbered revisions that never change. A dataset links to a Task, and every episode with no link of its own reads it.
This guide adds a robot, picks it as a dataset’s robot, then creates, publishes and links a Task.
Add a robot
Section titled “Add a robot”The Embodiments page lists robots. Click
New embodiment and choose a .urdf or .zip with its meshes (up to 256 MiB).
The robot opens while its model converts. The workspace’s oldest robot is the
default for handheld uploads that do not name one.
Configure a robot
Section titled “Configure a robot”Open a robot to see its 3D model and Configuration JSON. Pick a gripper or
choose Upload gripper to import a new workspace source. The upload stages the
selection; it does not change the robot until Save. Selecting a new gripper
opens the JSON with mounting fields for each arm. The picker includes grippers attached to other embodiments; Save makes an independent copy. Changing the selection while editing asks before discarding the current draft. A gripper with measured mounts for this robot previews immediately.
For other pairs, set attachment.parent_link and its transform to preview
the gripper. Ctrl+Space offers compatible mounting links, arm endpoints and
jaw joints in their JSON values. With two arms, the jaw joint is offered first as
a {side} template that maps the jaw on both arms, then as literal joint
names; a suggestion edits the draft and writes nothing until Save. A null parent leaves that
arm unmounted. Set the gripper link → TCP if it is not already calibrated. See
Configuration JSON for the fields and setup workflow.
Matrices are row-major 4×4 transforms in metres. A new TCP needs an explicit gripper URDF
link and matrix; no placement is guessed. Valid edits update the preview;
invalid JSON keeps the last valid preview. Discard drops the draft.
Saving can write the robot model and gripper copy in sequence. If a later step fails, the page says what was saved; reload before finishing the remaining configuration. Editing the robot’s owned gripper does not edit the workspace source. Replacing an owned gripper asks for confirmation. Use Manage grippers to delete a gripper; only the account owner can, and for everyone else Delete is greyed out. Deleting an attached gripper preserves its embodiment and other copies; a live dataset using it blocks deletion. The built-in handheld gripper offers Reset instead: it removes the gripper’s model and calibration, and an empty one returns. Older servers that do not support exact staged copying cannot save a staged selection.
The Solver page has its own JSON editor and Save and Discard controls. Saving configuration or solver changes marks earlier reach results stale; it does not run the solver again. Replace URDF imports a new model onto the same robot.
The robot card’s … menu offers Open, Copy, Rename and Delete. Only the account
owner can delete a robot; a dataset still played on it blocks deletion. The robot
cards and detail page do not list associated handheld uploads, but playback
associations remain stored.
Configuration JSON
Section titled “Configuration JSON”This is the dashboard editor’s schema; SDK and CLI operations have their own fields and methods. Use valid JSON without comments. Keep each existing arm exactly once; this editor does not add arms. Omitted settings retain their saved values, and unsupported fields are rejected.
arms[].sideidentifies an existing arm. Use the sides already in the document.arm_end_linkis the robot link at the end of the IK chain. It may differ from the physical attachment parent. If omitted, the saved endpoint is retained; an endpoint shared with an attachment follows its parent.attachmentcan be an object ornullto remove it. Itsparent_linkis the robot’s physical mounting link;built_inis true only when the robot URDF already includes the gripper; andtransformis the row-major 4×4 transform from that parent to the gripper link containing its TCP, with translation in metres. A built-in attachment uses the gripper link and identity transform.gripper_link_tcpmaps existing hand sides to row-major 4×4 matrices locating the TCP in the gripper link, with translation in metres. Keep the existing hand keys. When first configuring an unplaced TCP for a staged or robot-owned gripper, replace that hand’snullwith an object containinglink, a link in the gripper URDF, andmatrix, the transform. The editor accepts this object only for a first, unplaced hand.jawcan benullor an object withjoint,openandshut. Name an actual jaw joint and use its measured positions in the joint’s native units.tool_frameis an optional advanced legacy frame on an arm, separate from the gripper TCP. Itsxyz_mandrpy_radeach contain three numbers: translation in metres and roll, pitch, yaw in radians.
For example, this excerpt shows the shape of an initial TCP entry for a right hand. The link and identity matrix are illustrative, not a measured calibration; use the actual arm side, URDF link and measured transform for your gripper. Keep the rest of the existing document.
{ "gripper_link_tcp": { "right": { "link": "gripper_link", "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] } }}Choose or upload the gripper, configure its arm attachment and TCP, then review and Save. Use Move and Turn in the viewer when available, and use measured transforms or an imported calibration rather than guessing matrix values. Save writes the configuration; it does not run the solver.
For UMI recordings, set the shared tracking-controller → TCP calibration in
UMI calibration on an applicable robot page. On the dataset’s
Trajectories tab, move poses to the tool center point as needed, select the
robot, and run the solver. Robot solver settings have their own Solver page;
neither solver settings nor tracker_to_tcp belong in Configuration JSON.
See UMI calibration and
dataset setup for details.
For scripts and agents, see the Python SDK robot resource and CLI robot commands. Their interfaces are not the dashboard JSON schema above.
Copy a robot
Section titled “Copy a robot”Choose Copy… from a robot card. Name the copy and keep its gripper, pick a different source, upload one, or leave the flanges bare. A copied gripper belongs to the copy, so edits do not change the original robot. The copy is not the workspace default and does not take the original’s datasets or reach results. If a gripper cannot be attached, the new robot remains available to configure.
UMI calibration
Section titled “UMI calibration”On a robot carrying a gripper from the UMI capture rig, UMI calibration shows the shared capture gripper in 3D and edits its tracker → TCP transforms. Edit JSON opens left and right matrices in metres; Save validates and imports them using the captured revision, and Discard drops the draft. To create an initial calibration, use Import calibration and review the file before importing. Changes affect existing datasets only when their poses are moved again. A robot’s gripper link → TCP and the shared tracker → TCP are separate settings.
Pick the robot a dataset plays on
Section titled “Pick the robot a dataset plays on”The list shows each robot with the gripper it carries, for example
robot · gripper pair, or robot · its own gripper. The
gripper is picked on the robot’s page; a dataset picks only the robot.
A dataset with hand poses (a UMI recording, marked UMI · Beta) is set up on its trajectories tab, in the Setup strip at the top:
- Play on robot: pick the robot and its configured gripper from the list. The pick saves at once. Click (?) beside any row for what it means.
- Poses: one line says where the poses stand:
at the tool center point · 43 takes,moving to the tool center point,at the gripper root, or, when the picked robot has no TCP,at the gripper root · no TCP on this robot. Picking a robot whose arms all have a TCP moves the poses to the tool center point by itself, once, when they are not there yet. The move uses the calibration of the gripper the recording was captured with. The (?) explains the steps without equipment names. It starts nothing for a robot with no TCP (the line then offers Move to the gripper’s tool center point if you want it anyway), and never moves them back. While it runs, Run solver waits. The ⋯ menu has Move again and Back to the gripper root. - Solver: the IK solver for this dataset (it starts as the robot’s own), then Run solver. When it cannot be pressed, the reason is written beside it: no robot is picked, the poses are still being moved, the poses are at the TCP but the robot has no TCP, the setup is not verified, or your role cannot change the dataset. With the poses at the gripper root it can still be pressed. If where the gripper mounts on the robot is a guess, it warns you. If the robot or solver status could not be read, the row offers Retry setup check, which reads them again and changes nothing. Below it, Placement opens to Forward x, Left y, Up z (metres) and Heading (degrees), which move both hand paths together from the robot’s home midpoint. Click Save placement.
The solver runs only on takes tagged umi or egocentric. A dataset that holds
hand poses but carries neither tag has the strip, with Play on robot and Poses,
and no Solver row: there is no Run solver button and no solver
settings. Add the UMI tag on the dataset’s settings tab, page
collection, to get them.
Moving a merged dataset to the tool center point is not available yet. Its strip shows where its poses stand, read only. The overview of a UMI dataset links to Setup only while the setup is unfinished (no robot, a setup that is not verified), and says nothing once it is ready. Its settings tab, page collection, shows a read-only summary with a link to Setup.
Any other dataset (teleop, rollout, with no hand poses) has no Setup strip and no solver. Its
trajectories tab says Play on robot <robot> · <gripper> with Change robot (or Choose robot when none is selected), which
opens the picker on the settings tab, page collection, in the
Played on panel. It shows No robot when none is picked.
With no pick, a dataset shows the robot it was recorded on. Picking a robot
starts nothing: no reach run is queued and no issue is raised.
The same pick sets the gripper in the episode viewer’s trajectory card. The card
draws the Played on robot’s gripper at its TCP: the gripper the robot carries,
or its own fingers when it carries none, and says which in the line under its
title (robot · its own gripper). Change the pick and the card follows.
An upload that was merged into another dataset takes its robot from the merged dataset. Set it there.
If the account has no robots yet, the panel links to the Embodiments page.
Create and publish a Task
Section titled “Create and publish a Task”Tasks are on the Tasks page.
- Click + task. An
Untitled taskis created and opens. - Click the name at the top to rename it.
- Fill the fields on Overview. Description and Success are required.
| Field | What it holds, and how the checks use it |
|---|---|
| Description | What the robot does, e.g. “restock the shelf with bulbs from the crate”. The model reads it as the goal |
| Scene | The workspace, the objects that matter, how an episode starts, what varies. The model reads it to tell variation from a problem |
| Steps | The steps in order, one line per step. The model checks the order of actions against them |
| Failure | How a failure looks on camera, e.g. “a bulb falls off the shelf”. The model flags an episode that shows one |
| Success | How the end state looks when done, e.g. “every bulb rests on the shelf”. Every episode is checked against it |
Steps can repeat. One line per step is enough. Write a repeated motion once and say when it ends: “Pick a bulb from the crate and place it on the shelf. Repeat until the crate is empty.” Set min/max counts on the step in the graph. The graph is optional. It can be generated later from this text and reference takes, then edited by hand.
The draft saves itself. The status beside Publish says when it did, or
Not saved with a retry.
- Click Publish. In the dialog, write What changed (up to 1000 characters) and click Publish revision N.
Publish is greyed out when nothing changed since the last revision, or when something publishing needs is missing. Open the Info drawer: its Issues panel lists each gap. Click one to jump to where it is.
The other tabs:
- Graph: the steps as a state machine. Optional. When it has steps, it needs one start, a success outcome, every step reachable and no loops.
- References: pick example episodes from a dataset: 1–3 successes, and 1–2 takes per failure or recovery mode. Draft with VLM fills the fields from these picks for you to review. Estimate draft prices it first. It never publishes.
- Revisions: every published revision, newest first. Each one opens on its own page.
- Linked: the datasets and episodes in the workspace linked to this Task.
The Tasks list shows each task as draft, rev N, or rev N with
unpublished changes.
Link a Task to a dataset
Section titled “Link a Task to a dataset”On an upload’s or a merged dataset’s overview tab, the task panel shows the linked Task. A mixture has no picker: it reads the Tasks of its uploads.
- Click Select task (or Change task when one is linked).
- Pick the Task. The link saves at once.
- If some episodes link the old Task themselves, a dialog asks whether to move them too: Move them or Keep theirs.
A link is not a label. The episodes’ task label, which training reads as the
language instruction, stays as it is. To set the label too, use
qualia dataset assign-task below.
Link matching episodes in the Task’s … menu links every unlinked episode
and upload whose task label names the Task. Labels that are exactly the Task’s
name come ticked. Near misses (case, spacing, punctuation) are listed for you to
tick. Publishing a Task links the exact matches on its own.
From the CLI
Section titled “From the CLI”Every qualia task command acts in the API key’s own account; no --account
is needed. See
Authentication.
# create a draft, fill it, publish revision 1qualia task create --name "Cube in box" \ -d "Pick the cube off the table and put it in the box"qualia task edit <TASK_ID> --success "The cube rests inside the box"qualia task publish <TASK_ID> -m "First revision"
# link an upload to it: every episode with no link of its own reads itqualia dataset link-task <DATASET_ID> <TASK_ID>
# or label and link the kept episodes in one goqualia dataset assign-task -d <DATASET_ID> --task <TASK_ID> --filter 'state = KEPT'Use link-task to say which Task an upload was recorded against. It changes
no label. Use assign-task when the episodes also need the task label training
reads. See qualia task for every command.
There is no CLI command for robots or a dataset’s robot. Use the dashboard or the SDK.
From the SDK
Section titled “From the SDK”from qualia import Qualia
client = Qualia()draft = {"description": "Put the cube in the box", "success": "The cube is in the box"}task = client.tasks.create("Cube in box", draft=draft)client.tasks.publish(task.id, note="First revision")robot = "accounts/<ACCOUNT_UUID>/robots/<ROBOT_ID>"client.datasets.update("<DATASET_ID>", linked_task=task.name, target_robot=robot)The client acts in the API key’s own account; account= is an optional
override.