Skip to content

Commands

These flags go before the command and work with any command that calls the API. Each one overrides its environment variable, which overrides the config file that qualia auth login writes.

OptionEnv varDescription
--tokenQUALIA_API_KEYAPI key
--base-urlQUALIA_BASE_URLAPI origin, e.g. https://dev-api.qualiastudios.dev (default https://api.qualiastudios.dev)
--accountQUALIA_ACCOUNTOptional. Account UUID to act on; default is the API key’s own account (more)
--workspaceQUALIA_WORKSPACEWorkspace UUID to act in instead of the API key’s own workspace; never stored in the config file; rarely needed
Terminal window
qualia --token <API_KEY> credit
qualia task list # the API key's own account; no --account needed

qualia auth status shows the stored config and the environment variables, not these flags.


Show CLI and SDK versions.

Terminal window
qualia version

Save your API key, and optionally the API origin and an account, to the config file. Prompts for the key when --api-key is left out, and hides what you type.

Terminal window
qualia auth login --base-url https://dev-api.qualiastudios.dev
OptionDescription
--api-key, --tokenAPI key (prompted if omitted)
--base-urlAPI origin, no path. Default https://api.qualiastudios.dev; dev is https://dev-api.qualiastudios.dev
--accountOptional. Account UUID, lowercase; accounts/<uuid> also works. Default: the API key’s own account

Each login replaces the stored key, base URL and account. Leave out --base-url or --account and that value is no longer stored. Where the file lives and how to find your account id: CLI overview.

Show the stored login: whether a key is set (never the key), the base URL, and the account (the API key’s own unless one is stored).

Terminal window
qualia auth status
API key: configured
Base URL: https://dev-api.qualiastudios.dev
Account: the API key's own

It reads the config file and the QUALIA_* environment variables, not the global flags. It exits 1 with Invalid authentication config: … when the stored key or base URL is malformed. It does not call the API, so it does not prove the key works.


Show your current credit balance, and the split the billing page shows: starter credits, prepaid credits and each voucher, left of granted.

Terminal window
qualia credit
qualia credit --json
Credits: 1700
Starter: 80 of 100
Prepaid: 1,000 of 1,000
Voucher Launch: 620 of 1,000, expires 2026-12-31

The split is for members of the organization. When the key’s creator is no longer a member, only the total prints (null fields in --json).

Redeem a credit voucher for your organization, as the billing page does. Any member may redeem. The key needs the credits:write scope, and it must be an organization key: credits are the organization’s, so a workspace key is refused. Buying credits stays in the dashboard.

Terminal window
qualia credit redeem SPRING-2026
qualia credit redeem SPRING-2026 --json
Voucher redeemed: 1,500 credits added.

--json prints {"credits_granted": 1500, "account_id": "…"}. An unknown, used or expired code exits 1 with the reason the billing page shows, for example Error: [400] Voucher code has already been redeemed.


What people and their keys did: the dashboard’s Activity table. A workspace’s activity is the one --workspace names, else the key’s own; --org reads the whole organization’s, every workspace’s and its own. Reading needs data:read. A key restricted to workspaces cannot read activity.

List activity, newest first.

Terminal window
qualia activity list
qualia activity list --org --filter 'verb = KEEP AND actor = API_KEY' --json
qualia activity list --filter 'create_time >= "2026-10-01T00:00:00Z"' -n 100
OptionDescription
--orgThe organization’s activity, not one workspace’s
-f, --filterAIP-160 comparisons joined by AND: verb, actor (PERSON, API_KEY, …), workspace, text, create_time, subject, action
--rawEvery recorded event (action, summary), not only intentional actions
-n, --limitPage size; at most 100 for activity
--cursorThe nextPageToken of the previous page
--json{"activity": [...], "nextPageToken": ...} ({"events": [...]} with --raw)

The table names who acted where the record has a name, and prints each row’s event id. --json prints full event names.

Show one event as the record holds it. --details adds what it touched (its episodes and their state before) and the fields it changed.

Terminal window
qualia activity show <EVENT_ID>
qualia activity show accounts/<ACCOUNT>/workspaces/<WORKSPACE>/events/<EVENT_ID> --details --json

An id is read through the organization. A full name, which qualia activity list --json prints, works too.

Download the organization’s events record as JSON lines: one event per line, oldest first, every workspace’s and the organization’s own.

Terminal window
qualia activity export -o events.jsonl
qualia activity export -o october.jsonl --start 2026-10-01T00:00:00Z --end 2026-11-01T00:00:00Z
OptionDescription
-o, --outputWhere to write the file (required)
--startEvents created at or after it (RFC 3339, with a timezone)
--endEvents created before it
--json{"path": ..., "events": N}

The file is personal data: member events carry usernames and emails. It needs a key with audit:read, not restricted to workspaces, whose creator is an Admin or Owner. The file appears only once the whole record has arrived; a download that breaks leaves nothing behind.


The organization’s Hugging Face tokens: new runs use the default one.

Every command needs a key with the opt-in integrations:write scope (* does not grant it), made by an Admin or Owner of the organization, and not restricted to workspaces. A key’s value goes in once and is never shown again: the list prints its last four characters.

List the organization’s integration keys, newest first.

Terminal window
qualia integration list
qualia integration list --json
ID Provider Name Key Default Added
550e8400-e29b-41d4-a716-446655440000 huggingface ci ...9f3a yes 2026-10-30
660e8400-e29b-41d4-a716-446655440000 huggingface lab ...41bc 2026-10-29

--json prints {"integrations": [{"id", "provider", "name", "last4", "is_default", "created_by", "created_at", "expires_at"}]}. last4 is null for a key shorter than 12 characters.

Add a key. The key is piped in with --secret-stdin, or typed at a prompt that does not echo; on a terminal it always prompts. It is never taken from the command line, where it would stay in your shell history.

Terminal window
qualia integration add huggingface --name lab # prompts for the token
printf %s "$HF_TOKEN" | qualia integration add huggingface --name ci --secret-stdin --json
Argument / OptionDescription
PROVIDERhuggingface
--nameUp to 15 characters (required)
--secret-stdinRead the key from stdin; one trailing newline is dropped
--jsonPrint the key as it is listed

A Hugging Face token starts with hf_. The organization’s first token becomes the default.

Remove a key. Workspaces on a removed token move to the default.

Terminal window
qualia integration remove <ID>
qualia integration remove <ID> --yes --json

Without a terminal it needs --yes.

Make a Hugging Face token the one new runs use.

Terminal window
qualia integration default <ID>

Who is in the organization or a workspace, at which role, and changing it: the dashboard’s Members pages. Without --project a command is about the organization; with it, about that workspace.

A key needs the opt-in members:read scope to read and members:write to change (see Admin scopes); reading a space also takes projects:read. A key acts as the person who made it: it never gives a role above that person’s own, and only an admin or owner manages people. A workspace key acts only on its own workspace, so it always passes --project.

List everyone with access, their role and where it comes from: granted here, from the organization, or through a space’s members.

Terminal window
qualia member list
qualia member list --project <PROJECT_ID> --json
OptionDescription
-p, --projectA workspace; without it, the organization
--json{"space", "people": [...], "can_manage_members", "my_role"} as served

Show one person’s role on every space of the organization you can read, and the role granted on each. Needs an organization key.

Terminal window
qualia member show <USER_ID>

Give a person a role, or move them to another: on the organization, or on one workspace with --project. An organization role is for the organization’s members; invite anyone else. A workspace role raises a member above their organization role there, or makes someone a guest of it.

Terminal window
qualia member role <USER_ID> contributor
qualia member role <USER_ID> admin --project <PROJECT_ID> --json
Argument / OptionDescription
USER_IDThe person (required)
ROLEviewer, contributor, admin or owner
-p, --projectA workspace; without it, the organization
--jsonThe role before (from_role) and after, and the role they hold now

Take a person’s role on one workspace away (--project; they keep what the organization gives them), or remove them from the organization. --keep names the workspaces they stay a guest of. A key cannot remove the person who made it from the organization: leaving one takes a signed-in session.

Terminal window
qualia member remove <USER_ID> --project <PROJECT_ID> --yes
qualia member remove <USER_ID> --keep <PROJECT_ID> --yes
OptionDescription
-p, --projectA workspace; without it, the organization
--keepRemoving from the organization: a workspace they stay a guest of (repeatable)
-y, --yesSkip the confirmation (needed without a terminal)
--jsonWhat they hold now (effective_role), and the workspaces kept

Invitations to the organization or a workspace. The same scopes and rules as qualia member.

List the pending invitations: to one workspace with --project, or every one in the organization, each naming its space.

Terminal window
qualia invitation list
qualia invitation list --project <PROJECT_ID> --json

Invite someone by email at a role: to the organization, or to one workspace as a guest with --project. Never above your own role. Someone already in the organization gets a role with qualia member role instead.

Terminal window
qualia invitation send new@example.com --role viewer
qualia invitation send new@example.com --role contributor --project <PROJECT_ID>
Argument / OptionDescription
EMAILTheir email address (required)
-r, --roleviewer, contributor, admin or owner
-p, --projectA workspace; without it, the organization
--jsonThe invitation, with its id

Withdraw a pending invitation. Without --project it is found anywhere in the organization; a workspace key passes its own workspace.

Terminal window
qualia invitation withdraw <INVITATION_ID> --yes

List the datasets in your account, by name: uploads and merged datasets, or the kind you ask for. It reads the qualia.v1 Datasets API in the API key’s own account. An older qualia-sdk with no account set falls back to the older list route (uploads only).

Terminal window
qualia dataset list
qualia dataset list --search cube --dataset-type lerobot_v3
qualia dataset list --method umi --method teleop
qualia dataset list --tag gello --tag warehouse-a
qualia dataset list --kind mixture
qualia dataset list --kind all --filter 'merged_dataset = "accounts/<a>/datasets/<id>"'
qualia dataset list --limit 50 --json
OptionDescription
--limit, -nPage size, 1–100 (default 20)
--cursorPagination cursor printed by the previous page
--search, -qOnly names containing this text
--dataset-typeFilter: lerobot_v2_1, lerobot_v3, or mcap_ros2
--methodAny canonical tag; repeat to match alternatives
--tagAny collection tag; repeat to match alternatives
--kindupload, merged, mixture or all (default: uploads and merged)
--filterAn AIP-160 filter, ANDed on (state, labels.*, target_robot, …)

--filter 'merged_dataset = "<name>"' lists the uploads a merged dataset holds, which the list otherwise leaves out.

--dataset-type filters each page after it arrives, so a page can be shorter than --limit; follow the printed cursor to read on.

The Name column names each dataset as the dashboard does; a long name continues on the next line. On the older route (an old qualia-sdk) there are no names, so it shows the repository’s. --json also gives the repository (acct-<uuid>/<name>).

The Verdict column says what each upload amounted to: published, degraded (episodes were derived, but part of the upload was flagged) or underivable (no episode could be derived; the raw bytes are kept). Datasets published before verdicts existed show published. --json prints what the call returned: qualia.v1 Datasets with verdict and verdict_reason; on the older route, the older items with qds.ingest_verdict and qds.verdict_reason.

Edit this dataset’s collection metadata and custom tags. The recognized names are teleop, vr, umi, egocentric, policy-rollout, sim, real-world, human and gello; your own tags are accepted too. The set holds at most 64 distinct tags. A merged dataset changes only its own set, and an append preserves it. Version tags and episode curation tags are separate.

Terminal window
qualia dataset tags <dataset-uuid> --tag umi --tag real-world --tag human --tag gello
qualia dataset tags <dataset-uuid> --tag warehouse-a
qualia dataset tags <dataset-uuid> --clear

A changed, nonempty classification set updates saved metadata and customs in one atomic write. Custom-only input, or unchanged classifications with edited customs, replaces only customs and preserves declarations and inference. When classifications are present, echo them to remove customs without declaring inferred methods. --clear clears customs and explicitly makes every collection dimension Unknown, so inference cannot refill it. Omitting both --tag and --clear is an error. The command needs an account-scoped API connection and independent collection metadata support. The SDK reads the owner and uses its etag unless --etag was supplied; a stale caller etag is refused.

Replace the six-name compatibility view on an upload or merged dataset. A merged dataset changes only its own set. Other collection dimensions and free tags remain; use qualia dataset tags for the other dimensions and customs. The six tags are teleop, vr, umi, egocentric, policy-rollout and sim. Use --clear to explicitly record an empty set (Unknown); omitting all --method options is an error.

Terminal window
qualia dataset methods <dataset-uuid> --method umi --method teleop
qualia dataset methods <dataset-uuid> --clear

Show the account’s in-flight uploads, the feed the dashboard’s pending band renders, from any machine, including one that is not running the upload.

Terminal window
qualia dataset uploads
qualia dataset uploads --watch --every 30
qualia dataset uploads --json
OptionDescription
--watch, -wRefresh until Ctrl-C
--everySeconds between refreshes (default 15, never under 5)

Files and Bytes count content the lake has already accepted. Bytes go straight to storage, so a first upload of new content reads 0 until it publishes; Phase and Detail track the run throughout. Stop one with cancel-upload, and clear a failed one with dismiss-upload.


Publish a local dataset directory as a pinned DatasetVersion. Bytes go straight to storage; Qualia verifies the manifest and publishes the two together. Episodes become visible only once that publication succeeds.

Terminal window
qualia dataset upload ./my-recording my-dataset
qualia dataset upload ./teleop-session teleop-1026 --source-format mcap_ros2
qualia dataset upload ./umi-session umi-1026 --source-format mcap_ros2 --rig umi-handheld

--source-format takes lerobot_v2_1, lerobot_v3, or mcap_ros2. Leave it out and the format is read from the directory: codebase_version in meta/info.json tells LeRobot 2.1 from v3, and any .mcap makes it a session. LeRobot 2.1 is never aliased or converted to v3, so its source provenance stays distinct.

Use --source-format mcap_ros2 for a ROS 2 bag session. Lay it out as one subdirectory per recording, each holding its .mcap bags and, optionally, an episode.json sidecar carrying task and mode fallbacks. Every .mcap is ingested on its own, so rosbag2 split files (bag_0.mcap, bag_1.mcap, …) are accepted; see ROS 2 MCAP.

An MCAP session may carry meta/ingest.toml beside its bags, at the root of the directory you upload, to declare its state and action topics, its clock and its episode boundaries. Most teleoperated arms need none. See Declaring state and action channels and Declaring episode boundaries.

Use --rig umi-handheld for a handheld (UMI) recording. --rig names a gripper of your workspace: its name, its id, or its rig key (umi-handheld is the workspace’s UMI gripper). The server writes that gripper’s rig and TCP calibration into the upload’s meta/ingest.toml, so the recording converts to gripper poses as it lands. Your local file is never written. See Handheld (UMI) recordings.

Each upload is its own dataset unless you say otherwise. --merge-target appends this one upload to an existing merged dataset; pass its dataset id or its full resource name (accounts/{account}/datasets/{id}). A merged dataset is made with the SDK’s client.datasets.merge and is listed as merged by qualia dataset list. To append every upload to the same merged dataset, save it once with qualia dataset destination set; each upload then prints Upload destination: append to … on stderr. --standalone keeps one upload on its own even when a destination is saved. --merge-target and --standalone cannot be combined.

OptionDefaultDescription
--source-formatdetectedSource layout: lerobot_v2_1, lerobot_v3 or mcap_ros2; detected from the directory when omitted
--upload-workershalf your cores, 4–8Large (over 64 MiB) or edited files read and uploaded at once
--chunk-threads≈ half your coresThreads used to hash and split files
--quietoffSilence the live per-phase progress on stderr
--merge-targetsaved destinationAppend this upload to this merged dataset (id or resource name), for this run only
--standaloneoffKeep this upload its own dataset even when a destination is saved
--rignoneConvert a handheld (UMI) recording at this gripper as it lands: its name, id or rig key (umi-handheld)
--allow-underivableoffUpload an MCAP session even when no bag in it can be derived; a LeRobot structure refusal cannot be lifted
--jsonoffPrint the receipt as JSON on stdout (see the exit codes below)

Before a byte moves, an mcap_ros2 upload checks every bag for damage the server can never derive episodes from: a file too small to be MCAP, a bad leading magic, a cut before its first complete data record, or a record whose framing runs past the file. A well-formed bag with no messages is treated the same way. A damaged or empty bag does not stop the upload: it is listed, with the byte offset where it is known, and uploads as recorded; ingest reports it as source_underivable and the rest of the session publishes.

A bag cut after the recording started is listed as source_truncated when the part before the cut holds robot state, and the server derives the part that was recorded. By default one JointState message is enough. When meta/ingest.toml declares [state].topics, every declared topic needs a message before the cut; one missing topic makes the bag source_underivable (no_state), as does a cut bag with camera frames but no state. When the client cannot open the bag’s compressed chunks (lz4, zstd before Python 3.14, or a chunk too large to inspect), or cannot parse meta/ingest.toml, it lists the bag as source_truncated and the server decides; the server may still find no state and report no_state.

Only a session the server can derive nothing from, with no .mcap at all or every bag damaged or empty, stops the upload with exit code 1:

BLOCKED — 2 file(s) the server cannot derive; nothing was uploaded:
./session/episode-0/recording.mcap: truncated MCAP file (missing the trailing magic) — the recording did not finish [source_underivable]
./session/episode-1/recording.mcap: truncated MCAP file (missing the trailing magic) — the recording did not finish [source_underivable]
./session: every bag is underivable — no episode can be derived [session_no_episodes]
Re-run with --allow-underivable to upload the bytes as recorded.

With --allow-underivable the bytes upload anyway and are kept as a source dataset with no episodes. The receipt (--json) carries the check as preflight.

A LeRobot upload (lerobot_v2_1 or lerobot_v3) is checked the same way. The server refuses some structure outright, so these stop the upload with exit code 1, all listed in one run:

CheckCode
meta/info.json missing or not a JSON object; fps not in (0, 1000]; total_tasks not a positive integer; no features object; a video_path placeholder the server cannot render; lerobot_v2_1 without a positive chunks_sizeinfo_json_unreadable
codebase_version is not v2.1 for lerobot_v2_1 or v3.0 for lerobot_v3codebase_version_mismatch
no *.parquet file under data/data_shards_missing
lerobot_v2_1 without meta/episodes.jsonl or meta/tasks.jsonlinfo_json_unreadable

--allow-underivable cannot override these: the server refuses the structure whatever the flag says, so the upload stops with exit code 1 either way.

A camera whose video rate differs from the state and action row rate is accepted and flagged as video_rate_differs_from_rows; the viewer aligns them by time, but LeRobot download and fine-tuning require re-exporting the video at the row rate and uploading again.

A missing video does not stop the upload, and nothing is repaired for you. Paths come from video_path in meta/info.json, or the server’s default videos/{video_key}/chunk-{chunk_index:03d}/file-{file_index:03d}.mp4 when it has none. For lerobot_v2_1 every episode’s video is checked and each missing one is listed with its episode and camera; for lerobot_v3 each camera needs at least one file matching the template, and a camera with none is listed as missing from every episode. Both use camera_absent_for_episode: the upload continues, those episodes will be flagged, and you should probably exclude them. With no video for any camera, one warning says every episode will be flagged.

Every completed upload ends with a verdict, ingest_verdict in the --json receipt (with verdict_reason and verdict_source), and an exit code a script can branch on:

ExitVerdictMeaning
0published or degradedThe dataset published; degraded means an ingest finding, a flagged episode or an unreadable ingest report
1noneIt failed or was refused: a pre-flight block or an error
3underivableThe bytes are stored as a source dataset, but no episode could be derived

An underivable upload ends with one line on stderr naming the dataset that keeps the bytes and the reason:

UNDERIVABLE — no episodes could be derived; the bytes are kept as dataset <ID>. Reason: session_no_episodes: …

With --json, stdout carries the full receipt for a completed upload (exit 0 or 3) and {"preflight": …} for a pre-flight block (exit 1). Any other error prints nothing on stdout and exits 1 with its message on stderr.

Exit 1 does not mean nothing is left. A pre-flight block moves nothing, but after a transfer began the upload stays in qualia dataset uploads as failed, with its bytes.

Progress is written to stderr, so --json output stays pipeable. The server-side phases are bounded by silence rather than elapsed time: ingest parses every bag and transcodes every camera, so a large upload is free to take as long as it takes. See Configuration for the two environment variables that govern that wait.


A destination is a merged dataset that later uploads append to by default, so you do not pass --merge-target every time. It is saved in this CLI’s config file, bound to the API host, account and workspace it was saved under. An upload made under another host, account or workspace ignores it, stays standalone and says so on stderr.

Terminal window
qualia dataset destination set accounts/<account>/datasets/<id>
qualia dataset destination show
qualia dataset destination clear
CommandWhat it does
setSave TARGET, an existing merged dataset (its resource name or id), as the default --merge-target for later uploads
showPrint the saved destination with its API host, account and workspace; --json prints them as JSON
clearRemove the saved destination; later uploads are standalone again

set refuses a dataset that is not merged. A single upload can still go elsewhere with --merge-target, or stay on its own with --standalone.


Show which cameras a source dataset publishes and every degradation the ingest performed instead of failing. A camera missing from one bag is dropped from the whole dataset, so this is where a two-camera pin of a three-camera recording is explained. It opens with the upload’s report card: how many episodes were accepted, and which were flagged and why.

Terminal window
qualia dataset ingest-report <DATASET>
qualia dataset ingest-report <DATASET> --json
qualia dataset ingest-report acct-<ACCOUNT_UUID>/<NAME> --ref <COMMIT>
Argument / optionDescription
DATASETDataset id, full name or slug; or a canonical path acct-<uuid>/<name>
--refWith a path only: branch, tag or commit to read the report from (default: tip)

By id, name or slug the report is read through the qualia.v1 Datasets API; a merged dataset answers its uploads’ reports folded into one, and --json prints that API’s IngestReport. A path reads the older route. A report too large to read inline is an error, never shown as clean.


Download a dataset version in a format, or every file uploaded to the dataset, byte for byte (--format original).

Terminal window
# the newest version (stable), as LeRobot v3
qualia dataset download my-dataset
# one version, in each format
qualia dataset download my-dataset:1.0
qualia dataset download my-dataset:1.0 --format lerobot_v2_1
qualia dataset download my-dataset:1.0 --format mcap_ros2
# every file uploaded, byte for byte
qualia dataset download my-dataset --format original

DATASET is the dataset’s slug or id; add :<version> for a tag, stable (the newest) or a digest prefix. A full accounts/<account>/datasets/<dataset>/versions/<tag> name also works. Without a version you get the newest one.

DEST defaults to ./<slug>-<tag>, with -v21 for LeRobot v2.1 and -mcap for MCAP, and to ./<slug>-original for original.

Argument / optionDescription
DATASET<dataset>[:<version>], or a full version name
DESTDestination folder (optional)
--formatlerobot_v3 (default), lerobot_v2_1, mcap_ros2 or original; dashes work too (mcap-ros2)
--jsonPrint the result as JSON

original is every file uploaded to the dataset, byte for byte, with no version involved. It also holds what ingest stored beside those files: the annotations under meta/qds, meta/ingest_report.json and, for an MCAP upload, the LeRobot data and videos ingest made from the recordings. Trims and splits are not applied: the takes are whole, and a split’s pieces are only annotations under meta/qds. When the dataset has any, the command says how many on stderr and how to get the curated episodes (tag a version, then download it). Only an upload has files of its own, so a merged dataset or a mixture is refused: download one of its uploads, or a version. For now original needs an organization key; a workspace key is refused.

An MCAP download keeps only what was mapped at upload: tf, diagnostics and custom topics do not come back, so use original when you need them.

While the server builds a version (or, for original, lists the files) you see a spinner on stderr, then a bar with bytes, speed and files n/m. Files are checked as they arrive, and a run that stops keeps the files it checked: run the same command again and it fetches only the rest. Nothing is drawn with --json.

It ends with Saved <version> as <format> to <DEST> (<N> files, <size>), plus ; <K> kept from an earlier run when files were reused.

--json prints destination, format, reference, version, dataset_version_id, file_count, byte_count, downloaded_file_count, reused_file_count and materialization (the qualia.v1 Materialization). For original, reference is the dataset’s slug and version, dataset_version_id and materialization are null.

The first download of a version in a format starts its rendering, which needs a key that can write to the dataset (data:write); once it is rendered, downloads of it in that format need read access only (data:read). head, what a dataset yields right now, has no download: tag it first.

A version that contains a blocked episode (a NaN, an infinity, a missing value or a wrong width in its state or action rows) is refused, because a download carries every episode. Publish a curated version without them first, with qualia dataset curate <DATASET_VERSION_UUID> --idempotency-key <UUID> --name <NEW_DATASET>, and download that. --format original is not refused: it renders nothing, so it downloads the upload’s files, blocked episodes included.

The dashboard gives the command with the version filled in: Download on a dataset or version page.


Delete a mixture, or retire an upload or a merged dataset, for example after uploading the wrong folder. It leaves every list and every mixture, versions cut from it keep resolving, and no storage is reclaimed. A merged dataset is retired with the uploads it holds; the prompt says how many.

Terminal window
qualia dataset delete <FULL_DATASET_UUID>
qualia dataset delete accounts/<account>/datasets/<id> --force --yes
qualia dataset delete <FULL_DEFINITION_UUID> --definition --yes

The id must be the full UUID or the full name: qualia dataset list --json shows it as name (accounts/<account>/datasets/<id>). It is refused while a mixture reads the dataset, and while Tasks reference its episodes unless --force. On the older route (an old qualia-sdk) it retires uploads only.

OptionDescription
--forceAlso remove the Task references to its episodes (the Tasks stay)
--etagRefuse if the dataset changed since this etag
--definitionDelete a dataset definition instead; datasets are untouched
--yes, -ySkip the confirmation (required without a terminal)
--jsonPrint name, displayName, kind and deleted

Import one exact Hugging Face dataset commit server-side. The command confirms the pinned coordinates, submits them once, and polls while Hub bytes stream straight into storage. Success creates a pinned immutable DatasetVersion.

Terminal window
export HF_TOKEN="..." # optional for public datasets
qualia dataset import-hf \
qualia-robotics/openarm-cube-in-box-v1 \
17c29c487d886878ddcb3c5649101b2860fbc047 \
cube-in-box \
--source-format lerobot_v3

The revision must be lowercase 40-hex; branches, tags, URLs, and embedded credentials are rejected. HF_TOKEN is read only from the environment and is never accepted as a command-line option, printed, or sent in poll requests. Local file/byte/work-directory switches do not exist because no dataset body or scratch file touches the CLI machine. --json requires --yes so stdout stays valid JSON.

Save a lake query as a dataset definition, a target curate can publish a version into. qualia dataset pin <DEFINITION_UUID> freezes what it selects as an immutable version.

Terminal window
qualia dataset define kitchen-2026-09-16 --dataset-id <SOURCE_DATASET_UUID>
qualia dataset define audited-only --query ./query.json --description "human audited"
Argument / optionDescription
NAMEOne path segment: letters, digits, ., _, - (required)
--dataset-idSelect episodes of this source dataset; repeatable
--taskSelect one task
--tagRequire this tag; repeatable
--queryJSON file holding the complete saved query, instead of the flags
--descriptionFree text

--query takes the shape of the SDK’s DatasetSavedQuery: dataset_ids, task, tier, min_duration_s, max_duration_s, tags, review_state, search, numeric_predicates, predicates, episodes, query_text.


Freeze something as an immutable DatasetVersion. The printed DatasetVersion id is what training-features and curate take, and what the dashboard’s training launcher trains on.

  • pin DATASET TAG tags what an upload or a mixture yields now (qualia.v1 CreateVersion). Tags never move; a tag name is taken once per dataset. Acts in the API key’s own account (--account is optional).
  • pin DEFINITION_ID freezes what a definition’s saved query selects now. This stays on the /v1 path, because saved queries have no qualia.v1 equivalent.
Terminal window
qualia dataset pin <DATASET_UUID> 1.0 --note "first cut"
qualia dataset pin <DATASET_UUID> 1.1 --digest <HEAD_DIGEST_YOU_REVIEWED>
qualia dataset pin <DEFINITION_UUID> --note "first pin"
Argument / optionDescription
TARGETWith TAG: dataset id or full name. Without: a definition UUID
TAGTag name, e.g. 1.0: 1-64 of [0-9A-Za-z._-]
--noteWhat the version is
--digestWith TAG: the head digest you reviewed; refused if head moved

List a dataset’s tags, newest first.

Terminal window
qualia dataset version list my-dataset
qualia dataset version list my-dataset --json
Argument / optionDescription
DATASETDataset id, full name or slug
--filterAIP-160 filter over digest and create_time
--limit, -nPage size, 1-500 (default 50)
--cursorNext-page token
--json{"versions": [...], "nextPageToken": ...}

Show one version: its tag, reference, digest, episode counts, DatasetVersion id and note.

Terminal window
qualia dataset version get my-dataset:1.0
qualia dataset version get stable --dataset my-dataset --json

VERSION is <dataset>:<tag> (slug or UUID; a tag, stable, head or a digest prefix), a full version name, or a tag with --dataset.


What came in, went out or changed revision between two refs, and why. It also prints the note and the tag the dashboard’s tag dialog would offer.

Terminal window
qualia dataset version diff my-dataset # newest tag → head
qualia dataset version diff my-dataset --base 1.0 --target 1.1 --json
OptionDescription
--baseA tag, stable or a digest prefix; default the newest tag
--targetDefault head
--limit, -nChanged episodes per page, 1-1000 (default 100)
--cursorNext-page token

Tag what the dataset yields now. The tag never moves.

Terminal window
qualia dataset version diff my-dataset --json # read targetDigest
qualia dataset version create my-dataset 1.1 --note "dropped 3 jerky takes" --digest b3:…

--digest is the head digest you reviewed; if head has moved since, the tag is refused (409). qualia dataset pin DATASET TAG does the same without --digest.


Edit a version’s note, the one thing about a tag that changes.

Terminal window
qualia dataset version note my-dataset:1.0 "first cut, 120 takes"

--etag refuses the edit if the note changed since you read it.


A merged dataset’s merges, newest first, and the uploads each took. A merge is final: none can be reverted.

Terminal window
qualia dataset version merges my-merged-dataset --json

What was done to the dataset in the round a version opened: from its creation to the next tag’s (for head, since the newest tag). It lists rulings, edits, splits and issues, each with who did it and when, as the dashboard’s Curation of 1.0 panel does. A merged dataset’s record also reads the uploads it holds. At most 2000 events are read; a longer round shows its newest.

Terminal window
qualia dataset version record my-dataset:1.0
qualia dataset version record my-dataset:head --json

It reads the events of the dataset’s workspace.


Explain bad-data recommendations for immutable DatasetVersions without mutating them. Use --page-token to continue the result set.

Terminal window
qualia dataset curation-suggest <DATASET_VERSION_UUID>
qualia dataset curation-suggest <DATASET_VERSION_UUID> --json

Publish the reviewed analysis’s sealed recommendation set as a new immutable DatasetVersion. Supply a stable idempotency UUID. Source bytes and Git history are not deleted. Retrying with the same idempotency key resumes or recovers that publication’s receipt instead of suggesting fresh evidence against a head the first attempt already moved. A failed publication keeps its key: publish again under a new one.

Terminal window
qualia dataset curate <DATASET_VERSION_UUID> \
--definition-id <DATASET_DEFINITION_UUID> \
--idempotency-key <OPERATION_UUID> \
--yes

Omit --yes for an interactive confirmation.

Pass --name <NEW_DATASET> instead of --definition-id to publish the curated version as a new dataset. That is the form to use on an upload: an upload’s own dataset is source-owned and refuses a curated version. The curated version leaves out every episode the analysis recommends removing, not only blocked ones.


Show the exact camera, stream, timebase, and frame-timestamp descriptors for one immutable DatasetVersion. VERSION is <dataset>:<tag>, a DatasetVersion UUID, or a full version name. The output includes the resolved id; head must be pinned first.

Terminal window
qualia dataset training-features my-dataset:1.0
qualia dataset training-features my-dataset:1.0 --json
ArgumentDescription
VERSION<dataset>:<tag> (slug or dataset UUID), DatasetVersion UUID, or full version name (required)

Show the recorder markers inside one episode, in time order, in seconds from the start of the recording. Every edit command below cuts on these labels, so this is how you find out what a recording actually wrote.

The episode commands below speak qualia.v1, in the API key’s own account, and they name episodes through the upload they were recorded in: --dataset/-d with bare episode ids, or full names accounts/…/datasets/…/episodes/….

Terminal window
qualia dataset markers <EPISODE_UUID> -d <DATASET_UUID>
qualia dataset markers <EPISODE_UUID> -d <DATASET_UUID> --json

Cut episodes into children at their own markers, at given instants, or around windows to keep. Children are new episodes and the parents are left as they were, but a split is published when it answers and cannot be undone: dataset unsplit removes only children that were never published. Preview with --dry-run; once split, curate a child by trimming or rejecting it.

Terminal window
qualia dataset split <EPISODE_UUID> -d <DATASET_UUID> --cut-at grasp
qualia dataset split <EPISODE_UUID> <EPISODE_UUID> -d <DATASET_UUID> --cut-at grasp --dry-run
qualia dataset split <EPISODE_UUID> -d <DATASET_UUID> --at 12.5 --at 31
qualia dataset split <EPISODE_UUID> -d <DATASET_UUID> --keep 0.5-6 --keep 8-14 --dry-run
OptionDescription
--dataset, -dThe upload the episodes were recorded in (required)
--cut-atMarker label to cut at, as the recording wrote it
--atCut at this instant, in seconds from the start of the recording
--keepKeep this window as one child, START-END seconds, e.g. 1.5-9
--start-at-firstDrop the lead-in, up to the FIRST marker so labelled
--end-at-lastDrop the run-out, after the LAST marker so labelled
--dry-runPlan the cuts without writing them
--jsonJSON output

A request cuts one way: at markers, at instants or around windows. For markers, name at least one label across --cut-at, --start-at-first or --end-at-last. The narrowing options apply before the cut, which is how a lead-in is dropped; given alone, each episode becomes one trimmed child. All three accept repeats.

--at is for takes the recorder marked nothing at. Repeat it for several cuts; every named episode is cut at the same instants. It cannot be combined with the marker options. To find the instants, watch the take (dataset videos) or read it with the SDK’s episodes.sample_series.

--keep makes one child of each window and drops what lies outside every window: the lead-in, the run-out and the stretches between. Repeat it for several windows, in time order and not overlapping; every named episode keeps the same windows. It cannot be combined with --at or the marker options. The summary counts the frames no child keeps.

A trimmed episode is cut inside its trim: its children keep only the frames the trim keeps, what the trim cut is counted as dropped, and a marker or instant there cuts nothing.

An episode with no matching cut, or with children already, is left alone.


Delete the children of split episodes that were never published: those a split made before splits published. A published split is refused; curate its children by trimming or rejecting them.

Terminal window
qualia dataset unsplit <PARENT_EPISODE_UUID> -d <DATASET_UUID>

Trim episodes to their own markers, or to given seconds, reversibly. Each episode is narrowed to start at ITS first named marker and end at ITS last. The base extent never changes, so --clear restores it.

Terminal window
qualia dataset trim <EPISODE_UUID> -d <DATASET_UUID> --start-at-first ready --end-at-last done
qualia dataset trim <EPISODE_UUID> -d <DATASET_UUID> --start 1.5 --end 12
qualia dataset trim <EPISODE_UUID> -d <DATASET_UUID> --clear
OptionDescription
--dataset, -dThe upload the episodes were recorded in
--start-at-firstTrim the lead up to the FIRST marker so labelled
--end-at-lastTrim the tail after the LAST marker so labelled
--startStart each episode here, seconds from the start of the recording
--endEnd each episode here, seconds from the start of the recording
--clearRestore the full extent instead of trimming
--jsonJSON output

Use one way per call: marker labels, --start/--end, or --clear. --start or --end alone moves that end and keeps the episode’s other one (the whole recording when it was untrimmed). Each episode is read first and written with the etag it read, so an edit made in between is refused rather than overwritten. An episode the server will not trim, such as a split parent, is left alone with its reason.


Name each episode’s subtask spans from its own markers — the same boundary rule dataset split cuts on, used to label a span instead of carving it, so a whole selection can be named at once.

Terminal window
qualia dataset subtasks <EPISODE_UUID> -d <DATASET_UUID> --at grasp --at place
qualia dataset subtasks <EPISODE_UUID> -d <DATASET_UUID> --at grasp --starts-at
OptionDescription
--dataset, -dThe upload the episodes were recorded in (required)
--atMarker label whose presses bound a subtask (required, repeats)
--starts-atEach marker OPENS the span it names (default: it closes it)

Edit many episodes in one call: all of them change or none do, one revision each. Name the episodes and the fields they all take, or pass --from with a JSON list of per-episode edits (episode plus the fields to change, and an etag to refuse the call if that episode changed since you read it). Up to 500 episodes of one upload per call. Trim with dataset trim and link tasks with dataset assign-task or dataset link-episode.

Terminal window
qualia dataset edit <EPISODE_UUID>... -d <DATASET_UUID> --tag slow --outcome FAILURE
qualia dataset edit -d <DATASET_UUID> --from edits.json
OptionDescription
--dataset, -dThe dataset the episodes are read through (required)
--taskTask label
--instructionInstruction
--sceneScene
--tagReplace the tags with these (repeats)
--clear-tagsRemove every tag
--outcomeSUCCESS, PARTIAL, FAILURE or OUTCOME_UNSPECIFIED
--fromJSON list of per-episode edits; - reads stdin

Label episodes with a task and link them to it. In an upload it changes all of them or none. On a merged dataset it is all or none per upload: each upload commits on its own, so a failed call can leave earlier uploads changed. Rerun it to finish. With --task, every selected episode links to that Task and, without --label, takes its display name as the label: the language instruction training reads. A label alone sets the text and leaves links as they are.

Use it when the episodes need the label as well as the link. To only say which Task an upload was recorded against, use link-task.

Terminal window
qualia dataset assign-task -d <DATASET_UUID> --task <TASK_UUID> --filter 'state = KEPT'
qualia dataset assign-task <EPISODE_UUID> -d <DATASET_UUID> --label "restock shelf"
OptionDescription
--dataset, -dThe upload the episodes were recorded in (required)
--task, -tTask to link: id or accounts/.../tasks/...
--labelThe label; defaults to the task’s display name
--filterSelect episodes by filter instead of naming them
--jsonJSON output

Pass --task, --label or both. Name episodes or pass --filter, not both.


Set the Task an upload was recorded against. Every episode with no link of its own reads it, in one request. On a merged dataset it is set on every upload the dataset holds. A link, not a label: labels.task stays as it is, and a mixture can follow every upload linked to the task.

Episodes that link the old Task themselves keep it. Pass --relink to move them too.

Terminal window
qualia dataset link-task <DATASET_UUID> <TASK_UUID>
qualia dataset link-task <DATASET_UUID> <TASK_UUID> --relink
qualia dataset link-task <DATASET_UUID> --unlink
OptionDescription
--unlinkRemove the upload’s task link (omit the task)
--relinkAlso move the episodes linked to the old task themselves
--etagThe dataset’s etag as read; refuse the change if it moved since
--jsonJSON output

Link one episode to a Task, or remove its own link. A link, not an edit: the episode’s task label, revisions and versions stay as they are. Unlinked, the episode reads the Task of the dataset that holds it again. To label and link many episodes, use assign-task; to link a whole upload, link-task.

Terminal window
qualia dataset link-episode <EPISODE_UUID> -d <DATASET_UUID> --task <TASK_UUID>
qualia dataset link-episode accounts/…/datasets/…/episodes/… --unlink --json
OptionDescription
--dataset, -dThe dataset the episode is read through (with a bare id)
--task, -tTask to link: id or accounts/.../tasks/...
--unlinkRemove the episode’s own link
--etagThe episode’s etag as read; refuse the link if it changed since
--jsonJSON output

Pass --task or --unlink, one of them.


What the newest prepare run did to an upload, as the dataset page’s Tasks tab shows it: its state, error and warnings; the tasks discovery found, each with its episode count, health and the Task its episodes are checked against (a draft until published); and the dataset’s own task names, with their keys and the decisions on them. A merged dataset or a mixture has no run of its own.

Terminal window
qualia dataset preparation <DATASET_UUID>
qualia dataset preparation my-upload-slug --json

A found task with no Task prints the qualia task create line that makes one from its name and picked reference episodes, and the link-task (one task) or link-episode line that links its episodes. A Task id it prints is read with qualia task get and published with qualia task publish.

OptionDescription
--jsonJSON output

Decide which of the dataset’s own task names become tasks, as the Tasks tab’s Use these tasks. Every usable name gets a decision: the ones you pass with --use (or every one with --all) are used, the rest are recorded as a person’s no. Read-only names (outcome words, a code, already a task label) are never sent. The confirmed names start task discovery again, which drafts a Task for each; read it with qualia dataset preparation.

Terminal window
qualia dataset confirm-task-names <DATASET_UUID> --use ts_3f9a0c1b2d4e
qualia dataset confirm-task-names <DATASET_UUID> --all --name "ts_3f9a0c1b2d4e=Fold the towel"
OptionDescription
--use, -uUse this task name as a task, by its key (repeatable)
--allUse every task name that can be used
--nameKEY=NAME: the Task name, at most 32 characters. Default: the earlier one, else the first six words
--runThe run you read; refused when a newer run replaced it
--jsonJSON output

A personal API key decides as the person who made it. A workspace’s service key is refused.


List an episode’s edits, newest first, then the recording as revision 0. Each row names who edited, when, the note, and the fields the edit changed against the revision before it. Rulings (keep, reject) are not edits, and an episode nobody edited lists nothing. The history is the take’s: the same through every dataset that holds it.

Terminal window
qualia dataset history <EPISODE_UUID> -d <DATASET_UUID>
qualia dataset history <EPISODE_UUID> -d <DATASET_UUID> -n 10 --cursor <CURSOR> --json
OptionDescription
--dataset, -dThe dataset the episode is read through (with a bare id)
--limit, -nRevisions per page, 1–500 (default 50)
--cursorNext-page cursor from the previous page
--jsonJSON output: episodeRevisions and nextPageToken

Each revision in --json holds the take’s whole content after that edit.


Sign each camera’s video of an episode, or download them. Each link is short-lived and stops working at its expiry; run the command again for fresh ones. When a camera file holds more than the take, the take’s window in it is shown.

Terminal window
qualia dataset videos <EPISODE_UUID> -d <DATASET_UUID>
qualia dataset videos <EPISODE_UUID> -d <DATASET_UUID> --version stable --download ./videos
OptionDescription
--dataset, -dThe dataset the episode is read through (with a bare id)
--versionThe take as this version holds it: a tag, stable, v0 or a digest prefix
--downloadSave each camera’s video into this directory
--jsonJSON output; with --download, a downloads list of saved files

--download DIR creates DIR if needed and saves the whole file of each camera as DIR/<camera>.mp4, replacing a file of that name. A file is written under a temporary name and renamed once complete, so it is whole or absent. The links go to storage directly; your API key is never sent there. A take in no published version yet has no videos, and --download then exits 1.


List a dataset’s episodes, in recording order unless --order-by. The filter is the one the dataset page’s filter bar writes. Each line is one episode: its id (what the commands below take), index, standing, length after its trim, open issues and task label. Pass - as the dataset to read every dataset of the account; each line then starts with the episode’s full name.

Terminal window
qualia dataset episodes <DATASET_UUID>
qualia dataset episodes <DATASET_UUID> --filter 'state = UNREVIEWED AND open_issue_codes:"jerky"'
qualia dataset episodes <DATASET_UUID> --order-by 'metrics.duration_seconds desc' -n 20 --json
OptionDescription
--filterEpisode filter, e.g. state = KEPT, metrics.duration_seconds < 20
--order-byindex (default), record_time, metrics.<field> desc, open_issue_count desc
--viewbasic, or analysis to add each episode’s analysis
--versionRead the episodes as this version froze them: a tag, stable or a digest prefix
--limit, -nPage size, 1 to 1000 (default 50)
--cursorCursor from the previous page
--jsonJSON output: episodes, nextPageToken, totalSize

--version needs a qualia-sdk whose episode reads take version=; with an older one the command says so and exits 1.


Show one episode as its dataset sees it: standing and who ruled, task, labels, length, trim, subtasks, open issues, and who is editing it in the studio. Pass --dataset/-d with a bare episode id, or the full name accounts/…/datasets/…/episodes/….

Terminal window
qualia dataset episode <EPISODE_UUID> -d <DATASET_UUID>
qualia dataset episode accounts/<ACCOUNT>/datasets/<DATASET_UUID>/episodes/<EPISODE_UUID> --json
OptionDescription
--dataset, -dThe dataset it is read through (with a bare id)
--viewbasic, or analysis to add its analysis curves
--versionRead it as this version froze it
--jsonJSON output: the episode, including its etag

Count what a filter leaves: episodes, recorded time and frames, how many episodes carry each value of a field, and each metric’s quantiles, histogram and outlier fences. This is what the dataset page’s overview and outliers tab show.

Terminal window
qualia dataset summary <DATASET_UUID> --facet state --facet open_issue_codes
qualia dataset summary <DATASET_UUID> --filter 'state != REJECTED' --metric metrics.duration_seconds --bins 10
OptionDescription
--filterEpisode filter
--facetCount per value of this field, e.g. state, task, outcome, open_issue_codes (repeats; default state)
--metricDescribe this metric’s spread, e.g. metrics.duration_seconds (repeats)
--binsHistogram bins per metric (default 30); printed only when given
--jsonJSON output, every count included even when 0; an unfenced metric’s fences are "NaN"

Keep episodes in the dataset’s scope, closing their open issues there. Name the episodes, or pass --filter to keep everything it leaves, as the dataset page’s Keep does. Through a mixture the keep is the mixture’s own, and episodes its uploads do not keep are skipped.

Terminal window
qualia dataset keep <DATASET_UUID> <EPISODE_UUID> <EPISODE_UUID> --reason "checked by hand"
qualia dataset keep <DATASET_UUID> --filter 'state = UNREVIEWED AND open_issue_codes:"jerky"'
OptionDescription
--filterKeep every episode this filter leaves, not names
--reasonWords for the record
--jsonJSON output: every count of the result, and locked

The command prints how many episodes changed, were already kept, and were skipped, and how many open issues it closed. Name episodes or pass a filter, not both. An empty --filter "" is refused, so a blank shell variable never selects every episode.

A take a person has open in the studio is left as it was: their edit lease wins over a key. Those takes are listed on stderr with who holds them, and the command still exits 0. Run it again once they are done. --json puts the same list under locked (the first 100) beside lockedCount.


Reject episodes in the dataset’s scope: they leave training there. Nothing is deleted, and qualia dataset reset withdraws it. Same selection, output and locked takes as keep.

Terminal window
qualia dataset reject <DATASET_UUID> <EPISODE_UUID> --reason "operator in frame"
qualia dataset reject <DATASET_UUID> --filter 'metrics.duration_seconds < 2'
OptionDescription
--filterReject every episode this filter leaves, not names
--reasonWords for the record
--jsonJSON output

Withdraw the keep or reject made in the dataset’s scope, as Ctrl+Z does in the studio. Each episode then stands as derived: unreviewed while a blocking issue is open on it, kept otherwise. Issues the withdrawn keep closed open again. A reset carries no reason.

Terminal window
qualia dataset reset <DATASET_UUID> <EPISODE_UUID>
qualia dataset reset <DATASET_UUID> --filter 'metrics.duration_seconds < 2'
OptionDescription
--filterReset every episode this filter leaves, not names
--jsonJSON output

Put back episodes ingest validation rejected, with the reason the check was wrong. Made in the upload only. Episodes that are not validation rejects are skipped.

Terminal window
qualia dataset restore <DATASET_UUID> <EPISODE_UUID> --reason "the fps metadata was right"
OptionDescription
--reasonWhy the check was wrong (required)
--jsonJSON output

List a dataset’s issues and notes, oldest first. An issue blocks a keep until it is dismissed or its episode is ruled; a note never blocks. Through a mixture the list includes the issues upstream of it, under their own names; filter on dataset = "<the mixture's name>" for its own.

Terminal window
qualia dataset issues list <DATASET_UUID> --filter 'state = OPEN AND blocks = true'
qualia dataset issues list <DATASET_UUID> --episode <EPISODE_UUID> --json
Argument / optionDescription
DATASETDataset id or full name (required)
--filterAIP-160 over episode, code, kind, state, blocks, …
--episode, -eOnly this episode’s issues (id or full name)
--order-bycreate_time (default), create_time desc, code, episode
--limit, -nRows per page, 1-1000 (default 50)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

Count issues per code: open, the distinct episodes with an open one, and dismissed. The dataset page’s issues table. A person’s own words show as (own words).

Terminal window
qualia dataset issues summary <DATASET_UUID>
qualia dataset issues summary <DATASET_UUID> --filter 'blocks = true' --json
Argument / optionDescription
DATASETDataset id or full name (required)
--filterSame language as list
--jsonJSON output

Settle open issues by name or by filter: seen, and the episode wanted as it stands. No ruling moves. Notes and issues already dismissed are left alone. Issues on takes another person is editing stay open; the command prints how many it dismissed, then those takes and who holds them.

Terminal window
qualia dataset issues dismiss <DATASET_UUID> --filter 'code = "idle_tail"' --reason "fine for this task"
qualia dataset issues dismiss <DATASET_UUID> <ISSUE_UUID> <ISSUE_UUID>
Argument / optionDescription
DATASETDataset id or full name: the scope (required)
ISSUESIssue ids or full names; omit to select with —filter
--filterIssues matching this filter
--reason, -rWords for the record
--causeMANUAL (default), or TRIM when a trim cut it away
--jsonJSON output

Name issues or pass --filter, not both. Through a mixture only its own issues are dismissed.

Reopen dismissed issues by name or by filter. A person’s ruling on an episode whose blocking issue reopens is withdrawn: the episode is unreviewed again in this dataset. Takes another person is editing are left as they were and listed.

Terminal window
qualia dataset issues reopen <DATASET_UUID> --filter 'code = "idle_tail" AND state = DISMISSED'
Argument / optionDescription
DATASETDataset id or full name: the scope (required)
ISSUESIssue ids or full names; omit to select with —filter
--filterIssues matching this filter
--jsonJSON output

Raise an issue, or with --note write a note, in your own words, on an episode or the whole dataset. An issue on an episode withdraws a person’s ruling on it in this dataset; deleting the issue puts the ruling back.

Terminal window
qualia dataset issues add <DATASET_UUID> "Gripper slips at the second grasp" -e <EPISODE_UUID> --at 12.5
qualia dataset issues add <DATASET_UUID> "Recorded on the new rig" --note
Argument / optionDescription
DATASETDataset id or full name: the scope (required)
TEXTOne sentence; its first line is the title (required)
--episode, -eThe episode it is about; omit for the whole dataset
--noteWrite a note, which never blocks a keep
--atA moment in the episode, seconds from its start
--bodyMore than the sentence says
--request-idIdempotency key: a retry with it returns the first issue
--jsonJSON output

Withdraw an issue or note you raised. An API key withdraws only what it raised itself. An issue others replied to needs --force, which deletes their replies too.

Terminal window
qualia dataset issues delete <ISSUE_UUID> -d <DATASET_UUID> --yes
Argument / optionDescription
ISSUEIssue id or full name (required)
--dataset, -dThe dataset it is read through; needed with an id
--forceAlso delete replies others wrote under it
--yes, -ySkip the confirmation (required without a terminal)
--jsonJSON output

List the replies under an issue or note, oldest first.

Terminal window
qualia dataset issues replies <ISSUE_UUID> -d <DATASET_UUID>
Argument / optionDescription
ISSUEIssue id or full name (required)
--dataset, -dThe dataset it is read through; needed with an id
--limit, -nRows per page, 1-500 (default 50)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

Reply under an issue or note.

Terminal window
qualia dataset issues reply <ISSUE_UUID> "Trimmed it away" -d <DATASET_UUID>
Argument / optionDescription
ISSUEIssue id or full name (required)
TEXTWhat to say (required)
--dataset, -dThe dataset it is read through; needed with an id
--request-idIdempotency key: a retry with it returns the first reply
--jsonJSON output

Show one dataset: its kind, episode counts, robots, task link, tags, reach settings and etag. DATASET is an id, a full name or a slug (the dashboard address, /datasets/<slug>).

Terminal window
qualia dataset get kitchen-run
qualia dataset get <DATASET_UUID> --json

--json prints the qualia.v1 Dataset.


Change a dataset’s name, description, target robot or reach settings. Only what you pass changes. A merged dataset writes its target robot and reach settings to every upload it holds.

Terminal window
qualia dataset update kitchen-run --name "Kitchen, day 2" --description ""
qualia dataset update kitchen-run --target-robot <ROBOT_UUID>
qualia dataset update kitchen-run --reach-solver dls --reach-base 0,0.1,0 --reach-heading 0.5
qualia dataset update kitchen-run --reach-reset
OptionDescription
--nameNew display name
--descriptionNew description; '' clears it
--target-robotThe robot it plays on: a robot id or accounts/.../robots/...; '' clears
--reach-solverReach check IK solver: pyroki, dls, or auto (the robot model’s)
--reach-basex,y,z metres from the grippers’ midpoint in the robot’s frame, or auto
--reach-headingRotate both hand paths around world up, radians (within ±π)
--reach-resetClear all three reach settings
--etagRefuse if the dataset changed since this etag

The reach flags change one value at a time: the command reads the stored settings, changes what you passed and writes them back under the etag it read. Saving them starts nothing; the next reach check uses them.


Merge uploads into one dataset, or add uploads to a merged one. A merge is final: it cannot be undone. Preview it with --dry-run, which writes nothing.

Terminal window
qualia dataset merge day-1 day-2 --name "Bench" --dry-run
qualia dataset merge day-1 day-2 --name "Bench" --resolve target_robot=accounts/<a>/robots/<r>
qualia dataset merge day-3 --into bench --yes
OptionDescription
--nameName of the new merged dataset (or pass --into)
--intoAdd the uploads to this merged dataset
--descriptionDescription of the new merged dataset
--resolveAnswer a conflict: FIELD=VALUE, or channel_key:CHANNEL=KEY; repeatable
--dry-runList what differs between the uploads
--yes, -ySkip the confirmation (required without a terminal)

A blocking conflict (features, cameras, channel names, fps, where the poses are) settles only by leaving uploads out. The others take one value each: answer them with --resolve; labels and the task default to the uploads’ commonest.


Map native channel names onto canonical keys where the automatic grammar got them wrong, then derive the robot interface again. Renames add to earlier ones.

Terminal window
qualia dataset remap kitchen-run --rename /arm/joint_0=left.joint_0.pos --rename /arm/joint_1=

NATIVE= resets that channel to the key read from its name. A key another channel holds is refused and nothing is written: rename both to swap them.


Ingest an MCAP upload’s recordings again under a new meta/ingest.toml, or read a re-ingest that this command or resolve-poses started.

Terminal window
qualia dataset reingest kitchen-run --config ./ingest.toml --wait
qualia dataset reingest kitchen-run --status <REINGEST_ID> --wait
OptionDescription
--configThe complete meta/ingest.toml; it replaces the published one
--statusRead this re-ingest (its id or full name) instead
--waitWait until it succeeds or fails
--timeoutSeconds --wait waits (default 3600)

The upload’s next generation is published; the old one stays readable and versions cut earlier keep what they pinned. The published config again runs nothing. A config with [episodes] spans re-cuts the upload and is refused while any episode holds a person’s ruling, issue, note or edit. Mixtures, merged datasets and LeRobot uploads are refused.


Resolve a handheld upload’s poses at each hand’s tool centre point, with a gripper’s tracker-to-TCP calibration, or undo that with --root.

Terminal window
qualia dataset resolve-poses kitchen-run --gripper <GRIPPER_UUID> --wait
qualia dataset resolve-poses kitchen-run --root

The calibration is read and sent as it stands now; a gripper without one is refused before anything is sent. The work re-derives the whole upload, which takes as long as checking its video again. Without --wait, follow it with qualia dataset reingest <DATASET> --status <ID> --wait.

The same action as qualia dataset poses --at, which also finds the upload’s capture gripper.


Stop the upload feed reporting a failed or finished upload. The record of why it failed and the uploaded bytes are kept. A live upload is never hidden.

Terminal window
qualia dataset dismiss-upload <REPO_ID>
qualia dataset dismiss-upload <REPO_ID> --through <UPDATED_AT_UNIX>

REPO_ID is repo_id in qualia dataset uploads --json. --through is the updated_at_unix you saw, so a failure recorded after it stays. Organization keys only.


Cancel an upload in progress, from any machine. The uploading process is refused its next step and stops; server-side work stops on its next heartbeat. Nothing is published. Refused once the upload has published. Organization keys only.

Terminal window
qualia dataset cancel-upload <REPO_ID>

List the account’s server-side Hugging Face imports, show one, or cancel one. Organization keys only.

Terminal window
qualia dataset imports
qualia dataset imports <IMPORT_ID> --json
qualia dataset imports <IMPORT_ID> --cancel

Copy a dataset into another workspace, of this organization or another one. The copy is a new dataset whose history starts at the copied version, and it records where it came from. It shares the source’s content, so inside one organization no media bytes are written. It prints what it did:

Terminal window
qualia dataset copy fold-bench --to Bench
# Copied 4.0 GiB, 34 episodes in 0.8 s
# Fold bench: accounts/<account>/datasets/<copy-id>
qualia dataset copy <DATASET_UUID> --to "Partner Lab/Bench" --version v3 --name "Fold bench"
# Copied 4.0 GiB (12 MiB written), 34 episodes in 1.4 s

The dataset is found in the CLI’s workspace (--workspace or QUALIA_WORKSPACE, else the key’s own), by id, full name, slug or display name. --to <workspace> is a workspace of the key’s organization, by name or id. --to <org>/<workspace> names an organization and a workspace, each by name or id. An organization named by name resolves through the places this key can transfer to from the CLI’s workspace, so set --workspace or QUALIA_WORKSPACE for it; without one, name it by ids. A target the rule refuses prints the reason before anything is called.

Inside one organization you need read on the source and Contributor or higher in the target. Into another organization you need Admin or Owner in the source organization, and Contributor or higher in the target. A personal API key acts as its creator. A workspace or service key reaches only its own organization, and a key limited to some workspaces can target only those. A refusal prints the server’s reason and exits 1.

A tagged version that left episodes out is copied with new episode numbers, so the files that mix kept and left-out episodes are rewritten: tables always, and video too when the copy leaves the organization. A video that can’t be cut cleanly is re-encoded, and the result says its pixels changed.

Terminal window
qualia dataset copy fold-bench --to "Partner Lab/Bench" --version v3
# Request id 3f1c…: if this stops, run it again within 24 hours with --request-id 3f1c…
# Copying 26 episodes: 4 of 9 files.
# Copied 1.6 GiB (1.5 GiB rewritten, 3.0 GiB written), 26 episodes in 3 min

Such a copy can run past its call. The command waits and prints how far it got on stderr. Stopping the command stops nothing. The request id prints before the first request: run the same command with --request-id to pick the copy up again, within 24 hours of the first call. --request-id never starts a copy: if the server no longer holds that id, the command says the copy stopped and exits with status 1. Run it without --request-id to start again.

OptionDescription
--toTarget workspace: <workspace> or <org>/<workspace> (required)
--versionVersion tag to copy; default the current version
--nameName of the copy; default the source’s, or <name> (copy) if taken
--no-waitReturn at once with how far a running copy got
--request-idPick up a copy by the id it printed, with the same options, within 24 hours
--jsonJSON output: the dataset, counts, bytes and seconds

Move a dataset to another workspace of this organization. It keeps its id, name, history, versions, checks and flags. You need Admin or Owner in the source workspace and Contributor or higher in the target. A move is refused across organizations (copy instead), while a mixture in the source workspace reads the dataset, and when its name is taken in the target.

Terminal window
qualia dataset move fold-bench --to Bench
# Moved 4.0 GiB, 34 episodes in 0.1 s
OptionDescription
--toTarget workspace of this organization: name or id
--jsonJSON output: the dataset, counts, bytes and seconds

Set a dataset up for the reach solver: the robot it plays on, the solver and the placement. It does what the dashboard’s Setup strip does, so a handheld (UMI) dataset can be set up from a terminal or a pipeline. Only what you pass is written; the rest of the reach settings are kept, and repeating a command writes nothing.

Terminal window
qualia dataset setup <DATASET_UUID> --robot <ROBOT_UUID> --solver pyroki
qualia dataset setup <DATASET_UUID> --base 0 0 0 --heading 0
qualia dataset setup <DATASET_UUID> --robot <ROBOT_UUID> --wait
qualia dataset setup <DATASET_UUID> --run-solver

For a handheld upload, picking a robot with --robot also starts the resolve at the TCP, when all of this holds:

  • the dataset is an upload with handheld poses (not a mixture or a merged dataset);
  • every arm of the robot has a TCP (a robot with one bare arm would leave one hand at the gripper root and the other at the TCP);
  • the workspace has a gripper for the upload’s rig (the capture gripper, usually the UMI handheld) with a tracker-to-TCP calibration;
  • the poses are not at the TCP yet, or are there with another calibration.

The resolve uses the capture gripper’s calibration, not the robot’s own gripper’s: the robot only decides when. It re-derives the whole upload, so it takes as long as ingesting it did. Without --wait the command prints the operation and how to follow it (qualia dataset poses --follow). When nothing starts, the command says why and leaves the poses where they are.

The solver is never started by itself. --run-solver presses Run solver once, after waiting for a resolve this command started; follow the run with qualia check reach-status.

OptionDescription
DATASETDataset id or full name (required)
--robot, -rThe robot it plays on: id or accounts/.../robots/...; '' clears it
--solverpyroki, dls, or robot to follow the robot’s model
--base X Y ZWhere the takes’ start sits from the grippers’ midpoint: metres in the robot’s base frame, within 5 m
--headingRotate the paired paths around up, degrees (+/- 180)
--resolve / --no-resolveResolve the poses at the TCP whatever the robot / never (default: by the rules above)
--wait, -wWait for a resolve to finish (minutes to hours)
--run-solverPress Run solver afterwards
--jsonJSON output

Progress of a wait goes to stderr, so --json stays one document on stdout.


Show where a handheld upload’s poses are, or move them. Without --at it prints root (the gripper root’s poses), tcp (each hand’s TCP too) or recorded (a raw recording, which a resolve converts), the rig, the capture gripper, the calibration the poses were resolved with, and whether that gripper’s calibration has changed since.

Terminal window
qualia dataset poses <DATASET_UUID>
qualia dataset poses <DATASET_UUID> --at tcp --wait
qualia dataset poses <DATASET_UUID> --follow <OPERATION_ID>
qualia dataset poses <DATASET_UUID> --at root

--at tcp re-derives the upload with the capture gripper’s calibration (the same command again after the gripper’s calibration changed; with the same one it changes nothing), --at root goes back. A ruling or trim made while it runs fails it: run it again.

OptionDescription
DATASETDataset id or full name (required)
--attcp or root: move the poses (without it: show where they are)
--wait, -wWith --at: wait for the re-derive to finish
--followWait for a resolve you started without --wait: its id or operation name
--gripperWith --at tcp: resolve with this gripper’s calibration instead of the capture gripper’s
--jsonJSON output

A mixture is a dataset kept up to date from other datasets. It reads sources: a dataset by name, every upload with one label value, or every upload linked to a Task. A dataset source follows stable (its newest tag, the default), head (what it yields now), or is pinned to one tag. Tag a mixture with qualia dataset version create; delete one with qualia dataset delete.

Make a mixture with its sources, or from a version.

Terminal window
qualia mixture create "Folding, all rigs" \
--source dataset=rig-a-folding \
--source dataset=rig-b-folding@1.2 \
--source label=task:fold@head \
--source task=<TASK_UUID>
# a mixture that reads the dataset as version 1.0 froze it, to curate further
qualia mixture create --from rig-a-folding:1.0
OptionDescription
NAMEDisplay name; with --from optional
--source, -sRepeatable: dataset=<id, name or slug>[@stable|@head|@<tag>], label=<task|robot|operator|method|scene>:<value>[@stable|@head], task=<task>[@stable|@head]
--from<dataset>:<tag>: the dashboard’s Curate from this version. Not with --source
--descriptionFree text
--json{"mixture": {...}, "sources": [...]}

The sources are added together, or none of them. When they are refused, the mixture made stays and the error names it.


List a mixture’s sources in panel order: what each reads, how it follows it, its episodes and a newer tag when a pinned source has one.

Terminal window
qualia mixture sources folding-all-rigs --json

Remove a source from its mixture. Asks first; --yes skips the question.

Terminal window
qualia mixture remove-source accounts/…/datasets/…/sources/… --yes
qualia mixture remove-source <SOURCE_ID> --mixture folding-all-rigs --yes

Keep a dataset source on one tag of what it reads. A pinned source holds its dataset out of no merge, so an upload a mixture reads can then be merged.

Terminal window
qualia mixture pin-source <SOURCE_ID> --mixture folding-all-rigs
qualia mixture pin-source <SOURCE_ID> --mixture folding-all-rigs --tag 1.0

Without --tag it pins the dataset’s newest tag. It refuses when the source follows head and the dataset changed since that tag, since the pin would drop those changes; tag them first, or pass --tag to pin anyway.


The mixtures that read a dataset directly, each with how it follows it.

Terminal window
qualia mixture readers rig-a-folding --json

Register robots, import their models and give them a gripper. A robot owns its gripper: attaching one copies a gripper’s URDF, TCP and jaw into a gripper of the robot’s own, so lining it up or editing its TCP changes that robot only, and the copy is a snapshot (recalibrating the handheld later does not change it). A robot that carries a gripper never swaps it: to try another gripper, copy the robot. Every command takes --json, and a robot is an id, accounts/.../robots/... or its display name, looked up among robots only (show also finds gripper designs).

Terminal window
qualia robot list
qualia robot list --gripper

Robots oldest first (the first is the default target of a dataset). --gripper lists the workspace’s gripper designs, such as the handheld’s, and the copies robots own (each named like its source; the Owner column names the robot) instead. --limit (-n) and --cursor page.

Terminal window
qualia robot show <ROBOT_UUID>

The robot’s type, serial number, whether it has a model, the gripper it carries and where it sits on each arm (guessed until you set the mounts). For a gripper: its TCP, the calibration file and date, and the rig it was copied from.

The same as qualia robot show, for a caller that wants a robot: a gripper is refused, a display name is looked up among robots only, and the etag is printed.

Terminal window
qualia robot get <ROBOT> --json

Terminal window
qualia robot create "Lab arm" --type franka_fr3 --serial SN-1
qualia robot create "Lab arm" --urdf lab_arm.zip

--urdf also imports a file in one step, as New embodiment does: a .urdf, a .zip of the URDF and its meshes, or a directory. When the file never reaches an import, the robot made for it is deleted again; an import that starts and then fails keeps the robot, and the error names it. With --request-id the robot is kept, and running the command again follows the import instead of uploading again.

OptionDescription
NAMEDisplay name, unique in the account (required)
--type, -tRobot type key (franka_fr3, so101_follower); none for URDF-only
--serialSerial number, free text
--request-idIdempotency key (a UUID4) for a retry
--urdfImport this file in one step
--wait, --no-waitWith --urdf: wait for the conversion (default on)
--timeoutWith --urdf: seconds to wait (default 1800)
Terminal window
qualia robot import <ROBOT_UUID> lab_arm.urdf
qualia robot import <ROBOT_UUID> ./rizon_description # a directory is zipped
qualia robot import <ROBOT_UUID> rizon.zip --no-wait

Replaces the robot’s model with a .urdf, a .zip of the URDF and its meshes, or a directory (hidden VCS folders are left out). The file is uploaded (at most 256 MiB) and the server converts the meshes: a second for a URDF, minutes for a large mesh package. The command waits and prints each state on stderr; --no-wait returns once the import is accepted, and --timeout bounds the wait (seconds, default 1800). A URDF the server cannot use ends failed and the command exits 1 with the server’s reason. A file symlinked within a directory is zipped with its content; a link to a file outside it, a link to a directory or a broken link is refused by name.

Terminal window
qualia robot model <ROBOT_UUID>
qualia robot model <ROBOT_UUID> --solver dls --reach-base 0 0 0
qualia robot model <ROBOT_UUID> --arms-file arms.json

Without an option it prints the model: the import state, solver, each arm’s hand link and TCP, the jaw and the reach base. Options change only what they name.

OptionDescription
--solverpyroki or dls
--arms-fileA JSON list of arms {"side": "left", "hand_link": "...", "tool": {"xyz": [], "rpy": []}, "start_posture": []}; replaces all
--reach-base X Y ZWhere a dataset’s reach check starts when it names no base: metres in the robot’s base frame, within 5 m
--clear-reach-baseRemove it
--etagRefuse if the model changed since this etag
Terminal window
qualia robot copy <ROBOT_UUID>
qualia robot copy <ROBOT_UUID> --name "Lab arm, parallel gripper" --gripper <GRIPPER_UUID>

Makes a new robot from an existing one, to try another gripper or a mount without touching the original. The copy takes the robot’s type, URDF and meshes, arms, solver, jaw, reach base and capsules and a gripper of its own, and shares nothing with it afterwards; its serial number, datasets, reach results and history are not copied. --gripper is keep (the default: a copy of the gripper it carries, with its mounts), none, or a gripper or robot to copy a gripper from instead (mounted at each arm’s hand link: line it up with qualia robot gripper mount). keep and none are matched in any case; any other value must be a robot id (a UUID) or resource name, and is checked before the copy is made. A copy is refused while the model is being imported or the capsules fitted: try again in a minute.

With another gripper this is two calls, the copy and then the attach. If the attach fails, the gripper-less copy stays: the command exits 1 with the attach’s own error and a note naming the copy, which you can give a gripper with qualia robot gripper attach <COPY> --copy-from ... or delete. Run again with the same --request-id to retry; a copy that already carries a gripper is returned as it is.

qualia robot rename and qualia robot delete

Section titled “qualia robot rename and qualia robot delete”
Terminal window
qualia robot rename <ROBOT_UUID> "Lab arm 2"
qualia robot delete <ROBOT_UUID> --force --yes

Deleting a robot deletes the gripper it owns, files included. It is refused while the robot has a model unless --force; datasets that played on it keep a dangling reference. It asks first, or pass --yes. With --json it prints {"robot": ..., "deleted": true, "force": ...}.


Edit a robot’s name, type or serial number. '' clears a type or serial. For the name, qualia robot rename is the same action.

Terminal window
qualia robot update <ROBOT> --name "Lab arm 2" --serial SN-0042
OptionDescription
--nameNew name
--typeRobot type key, e.g. franka_fr3
--serialSerial number
--etagRefuse if changed since this etag
--jsonJSON output

Correct what the import guessed. Only what you pass changes. The command reads the model and saves under its etag, so a change made meanwhile is refused. qualia robot model edits the arms and solver too, and qualia robot gripper jaw the jaw.

The jaw lives in the model of the gripper the robot carries, so --jaw-* and --no-jaw write there: a second write when you also change the arms or solver. --etag covers the robot’s model only. With --json a command that wrote both adds the gripper’s model as carriedGripperModel.

Moving an arm’s hand link starts its posture at rest unless --home sets it, and moves the carried gripper’s mount on that arm along, as the Embodiments page does.

Terminal window
qualia robot configure <ROBOT> --arm left=left_link7 --arm right=right_link7
qualia robot configure <ROBOT> --home right=0.2,0,0,0,0,0
qualia robot configure <ROBOT> --solver dls --jaw-joint '{side}_finger_joint1' --jaw-open 0.8 --jaw-closed 0
OptionDescription
--armAn arm’s hand link: left=LINK or right=LINK (repeatable)
--homeAn arm’s home posture, radians, one per turning joint: left=a,b,…
--solverIK solver: pyroki or dls
--jaw-jointThe joint that opens the jaw; {side} is left or right
--jaw-openIts position fully open
--jaw-closedIts position shut
--jaw-homeIts position at home
--no-jawClear the jaw joint
--etagRefuse if the robot’s model changed since this etag
--jsonJSON output

Give a robot a gripper, set the mounts of the one it carries, or take it off, in one command. It does what qualia robot gripper attach --copy-from, mount and detach do.

On a robot that carries none, GRIPPER is copied and the copy is the robot’s own. With no --mount or --baked, it creates a mount at each arm’s hand link with no offset, for each hand the gripper has a TCP in a link for. A gripper with no such TCP gets no mount; set one with qualia robot gripper tcp or calibration, then qualia robot gripper mount.

Naming the gripper the robot carries sets its mounts; without --mount each arm keeps a mount that still hangs on its hand link. Any other gripper is refused: a robot never swaps its gripper, so qualia robot copy it with the other one. --none deletes the robot’s own gripper: it asks first, or pass --yes.

Terminal window
qualia robot carry <ROBOT> <GRIPPER>
qualia robot carry <ROBOT> <ITS_GRIPPER> --mount left=left_link7:left-mount.json --baked right
qualia robot carry <ROBOT> --none --yes
OptionDescription
--noneTake the gripper off, which deletes it
--mountleft=LINK or left=LINK:matrix.json: the gripper’s hand link in LINK’s frame, 16 numbers row-major, metres (default identity). Repeatable
--bakedleft or right: the robot’s URDF has the gripper built in on that arm
--etagRefuse if changed since this etag
--yes, -yWith --none: skip the confirmation
--jsonJSON output

List the datasets played on a robot (their target robot). Takes --limit, --cursor and --json.

Terminal window
qualia robot datasets <ROBOT>

Some actions have two commands. Both work; the last column says what differs.

CommandAlsoWhat differs
qualia robot showqualia robot getget refuses a gripper and prints the etag
qualia robot renamequalia robot update --nameupdate also takes --type, --serial and --etag
qualia robot model with optionsqualia robot configureconfigure sets one arm at a time, the jaw, and moves mounts with an arm
qualia robot gripper jawqualia robot configure --jaw-*configure changes one jaw field at a time
qualia robot gripper attach --copy-from, mount, detachqualia robot carryOne command; see above
qualia robot gripper tcp --filequalia gripper tcpgripper tcp takes a design or a robot, by name among designs
qualia robot gripper calibrationqualia gripper calibrateThe same
qualia robot list --gripperqualia gripper listThe same rows, with the TCP state and rig key
qualia robot show <GRIPPER_ID>qualia gripper getget refuses a robot and looks a name up among designs
qualia robot import <GRIPPER_ID> FILEqualia gripper importgripper import refuses a robot and looks a name up among designs
qualia robot delete <GRIPPER_ID> --forcequalia gripper deletegripper delete refuses a robot, always forces and looks a name up among designs
qualia dataset poses --atqualia dataset resolve-posesposes also finds the capture gripper

The robot’s own gripper. Each command takes the robot that carries it.

Terminal window
qualia robot gripper attach <ROBOT_UUID> --copy-from <GRIPPER_UUID>
qualia robot gripper attach <ROBOT_UUID> --urdf ./parallel_gripper
qualia robot gripper mount <ROBOT_UUID> -m left:left_hand:0,0,0.02 -m right:right_hand:0,0,0.02
qualia robot gripper jaw <ROBOT_UUID> --joint '{side}_finger_joint' --open 0.04 --shut 0
qualia robot gripper tcp <ROBOT_UUID> --hand 'left:gripper_{side}_ee:0,0,0.12' --hand 'right:gripper_{side}_ee:0,0,0.12'
qualia robot gripper calibration <ROBOT_UUID> tcp_calibration.json
qualia robot gripper detach <ROBOT_UUID>

attach gives a robot that carries none a gripper. --copy-from copies a gripper design (the handheld’s, a library gripper) or another robot’s own gripper: its URDF and meshes, TCP and jaw as they are now. --urdf uploads a gripper of the robot’s own (a .urdf, .zip or directory) and imports it; it has no TCP yet, so set one before you mount it. A robot that carries a gripper is refused: qualia robot copy it with the other gripper, or detach first.

mount sets where the gripper sits on each arm and replaces all mounts, one per arm at most. A mount is SIDE:LINK[:X,Y,Z[:ROLL,PITCH,YAW]], the position in metres and the rotation in radians (URDF convention) of the gripper’s hand link in LINK’s frame, where LINK is a link of the robot joined to the arm’s hand link by fixed joints only; SIDE:baked says the robot’s own URDF already has the gripper built in. The gripper’s hand needs a TCP in a link first. attach --copy-from takes --mount too; without it the copy is mounted at each arm’s hand link with no offset, guessed.

jaw names the joint that opens the gripper ({side} stands for left or right) and its position open and shut, checked against the URDF’s limits, and optionally --home, its position at the arm’s home (never inferred; left out, the home the model already has for the same joint is kept). It edits the model the jaw lives in: the carried gripper’s, or the robot’s own when its URDF has the gripper built in or it carries none.

tcp sets the TCP of each hand, SIDE:LINK:X,Y,Z[:ROLL,PITCH,YAW] in a link of the gripper’s URDF ({side} in a link stands for the side); a hand keeps its link once set, and hands not named keep theirs. Or --file a JSON of {"left": {"link": "...", "matrix": [... 16 numbers ...]}, "right": {...}}. calibration replaces the TCPs with a tcp_calibration.json. detach takes the gripper off, which deletes it: its URDF, meshes, TCP and jaw.

On a workspace that has not been migrated yet, a robot may still carry a gripper shared with other robots. jaw, tcp and calibration refuse to edit it by way of the robot (the error names the gripper), because the edit would change every robot that carries it; pass the gripper’s id instead of the robot’s to edit it for all of them. mount is not affected: mounts are the robot’s own.

OptionDescription
--copy-from / --urdfattach: where the gripper comes from (exactly one)
--nameattach --urdf: the gripper’s name
--mount, -mattach --copy-from, mount: a mount, repeat per arm
--joint, --open, --shut, --homejaw: the joint and its positions
--hand, --filetcp: the hands’ TCPs
--filenametcp, calibration: the name recorded with the TCP
--etagRefuse if it changed since this etag
--yes, -ydetach: skip the confirmation

Gripper designs: one gripper’s URDF and the tool centre point (TCP) of each hand on it. A robot takes a copy of its own (qualia robot gripper attach --copy-from, qualia robot carry), so changing a design reaches no robot that already has a copy. A gripper with a model and a calibration can be a handheld rig, whose uploads are resolved at its TCP. A display name is looked up among designs only, never among the copies robots own (they are named like their source): name a copy by its id, or use qualia robot gripper.

List the workspace’s gripper designs, oldest first, with whether each has a TCP. The copies robots own are listed too, named like their source; Owner is the robot that carries one. Same list as qualia robot list --gripper. Takes --limit, --cursor and --json.


Show a gripper: its rig key, whether uploads resolve with it, the calibration file and date, and each hand’s link and tracker-to-TCP.

Terminal window
qualia gripper get <GRIPPER>

Register a gripper design from its URDF or .zip, as ”+ gripper” does. The name defaults to the file name; a taken name is refused. When the file never reaches an import, the gripper made for it is deleted again. Takes --name, --wait/--no-wait, --timeout (default 600) and --json.

Terminal window
qualia gripper create parallel_gripper.urdf

Import a new URDF onto a gripper. A TCP set in one of its links goes stale until you set it again. Takes --wait/--no-wait, --timeout and --json.


Delete a gripper design and its model (account owners only). Robots that copied it keep their copy. A robot’s own gripper, named by its id, can be deleted too: it comes off its robot, as qualia robot gripper detach does, unless a live dataset still plays back with it. A workspace’s “UMI handheld” is an ordinary gripper: a delete removes it for good. Pass --yes when there is no terminal.


Set where the TCP is on each hand: a 4x4 matrix in one of the gripper’s URDF links. Hands the file leaves out keep theirs. At most 64 KiB. Same action as qualia robot gripper tcp --file, which takes the robot.

Terminal window
qualia gripper tcp <GRIPPER> tcp.json
{
"left": {
"link": "{side}_ee_base_link",
"matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0.1, 0, 0, 0, 1]
},
"right": {
"link": "{side}_ee_base_link",
"matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0.1, 0, 0, 0, 1]
}
}

matrix is 16 numbers, row-major, metres, or a nested 4x4. {side} in a link is replaced by left or right.

OptionDescription
--filenameWhat to call the calibration; default tcp-matrix:<gripper>
--etagRefuse if the TCP changed since this etag
--jsonJSON output

Import a handheld rig’s tcp_calibration.json: each hand’s tracker-to-TCP, and the TCP in the gripper’s end-effector link where the file gives it. It replaces the gripper’s TCP. Takes --filename, --etag and --json. Same action as qualia robot gripper calibration, which takes the robot.

Terminal window
qualia gripper calibrate <GRIPPER> tcp_calibration.json

Manage tasks: what a robot should do and how success shows. A task is a draft of five fields (description, scene, steps, success, failure) and an optional procedure, published as numbered revisions that never change. The Robots and Tasks guide walks through it.

Every qualia task command acts in the API key’s own account; a key acts in no other, so --account and QUALIA_ACCOUNT are not needed. See Authentication. A task is named by its id or its full name, accounts/<ACCOUNT_UUID>/tasks/<TASK_ID>.

List the account’s tasks, newest first, with their latest revision and whether the draft has unpublished changes.

A key restricted to workspaces reads no tasks.

Terminal window
qualia task list
qualia task list -n 100
OptionDescription
--limit, -nPage size, 1–500 (default: 20)
--cursorPagination cursor
--jsonJSON output

Show a task with its draft, or one of its published revisions. --json prints the task as the API returns it; edit that file and pass it to qualia task edit.

Terminal window
qualia task get <TASK_ID>
qualia task get <TASK_ID> -r 2
qualia task get <TASK_ID> --json > task.json
OptionDescription
--revision, -rShow this published revision instead
--jsonJSON output

Create a task. Its draft comes from a file or from --description. Nothing is published. A task needs a name: --name, or displayName in the file.

Terminal window
qualia task create --name "Cube in box" -d "Pick the cube off the table and put it in the box"
qualia task create task.yaml --name "Cube in box"

The file is YAML or JSON. It holds either a task as qualia task get --json prints it (displayName, draft, references), or only the draft fields:

description: Pick the cube off the table and put it in the box
scene: A cube and an open box on a table; the cube's start position varies
steps: |
Grasp the cube
Move it over the box
Release it
success: The cube rests inside the box
failure: The cube falls outside the box
OptionDescription
--nameDisplay name (overrides the file)
--description, -dWhat the robot should do
--successA picked success reference episode (repeatable, 1–3)
--failureA picked failure reference, MODE=<episode> (repeatable)
--recoveryA picked recovery reference, MODE=<episode> (repeatable)
--jsonJSON output

Reference episodes are full names, accounts/.../datasets/.../episodes/.... Pick them in the file or with options, not both.


Save a task’s draft from a file, or single fields from options. A file replaces the whole draft, procedure included. An option replaces only that field, and "" clears it. Published revisions never change.

Terminal window
qualia task edit <TASK_ID> --success "The cube rests inside the box"
qualia task edit <TASK_ID> --steps $'Grasp the cube\nRelease it over the box'
qualia task edit <TASK_ID> task.json
OptionDescription
--nameNew display name
--descriptionWhat the robot should do
--sceneThe scene the task runs in
--stepsThe steps, one per line
--successHow success shows
--failureHow it fails
--etagRefuse if the task changed since this etag
--jsonJSON output

Pass a draft file or field options, not both. A file from qualia task get --json carries the task’s etag, so the save is refused if someone changed the task since.


Publish the draft as the next revision. It needs a description and a success; the other fields are optional. A procedure, when there is one, must have one start, a success outcome, every step reachable and no loops. Publishing also links the unlinked episodes and uploads whose task label is exactly the task’s name.

Terminal window
qualia task publish <TASK_ID> -m "First revision"
OptionDescription
--note, -mWhat changed
--etagPublish only the draft as read at this etag
--jsonJSON output

List a task’s published revisions, newest first: number, note, content hash, who published it and when.

Terminal window
qualia task revisions <TASK_ID>
OptionDescription
--limit, -nPage size, 1–500 (default: 20)
--cursorPagination cursor
--jsonJSON output

Link the unlinked episodes and uploads whose task label names the task. It lists the labels that match exactly beside the near misses (case, spacing, punctuation) in your workspace. Without --label it links the exact matches; with it, the labels you pass. A link already set is never changed, and labels stay as they are.

Terminal window
qualia task link-episodes <TASK_ID> --dry-run
qualia task link-episodes <TASK_ID> -l "cube in box" -l "Cube in box."
OptionDescription
--label, -lA label to link, exactly as listed (repeatable)
--dry-runList the matching labels and link nothing
--jsonJSON output

Delete a task. Only account owners can. A task with a published revision is refused unless you pass --force, which deletes its revisions too. It asks for confirmation; pass --yes when there is no terminal.

Terminal window
qualia task delete <TASK_ID>
qualia task delete <TASK_ID> --force --yes
OptionDescription
--forceDelete its published revisions too
--etagRefuse if changed since this etag
--yes, -ySkip the confirmation

Show the episodes a person picked for a task as references: each one’s id, role (success, failure, recovery), mode and episode.

Terminal window
qualia task references <TASK_ID>
OptionDescription
--limit, -nPage size, 1–500
--cursorPagination cursor
--jsonJSON output

Pick an episode as one of the task’s references, as yourself. A task holds 1 to 3 success references and any number of failure and recovery modes, each with 1 or 2. A failure or recovery names its mode; a success has none. You need read access to the episode’s dataset.

Terminal window
qualia task reference add <TASK_ID> accounts/<ACCOUNT_UUID>/datasets/<DATASET_ID>/episodes/<EPISODE_ID>
qualia task reference add <TASK_ID> <EPISODE_NAME> --role failure --mode slip --start 1.5 --end 4
OptionDescription
--rolesuccess (default), failure or recovery
--modeThe failure or recovery it shows (1–80 characters)
--startRange start, seconds into the episode (with --end)
--endRange end, seconds (with --start)
--jsonJSON output

The episode is its full name, as qualia task references --json or Episode.upload names it.


Remove a reference from the task. The episode is untouched. It asks for confirmation; pass --yes when there is no terminal.

Terminal window
qualia task reference rm <TASK_ID> <REFERENCE_ID> --yes
OptionDescription
--yes, -ySkip the confirmation
--jsonJSON output ({} on success)

Ask a VLM to draft the task’s fields from exactly its picked references. It never publishes. --estimate prices it and starts nothing.

Terminal window
qualia task draft <TASK_ID> --estimate
qualia task draft <TASK_ID> --wait
OptionDescription
--modelVLM model
--max-costCredit cap
--estimatePrice the whole selection; start nothing
--waitWait for the stored proposal
--jsonJSON output

A draft needs a signed-in person: with an API key, --estimate and the draft are refused (a person must draft a Task).

qualia task draft-get <DRAFT> reads a stored proposal and changes nothing. qualia task draft-apply <DRAFT> saves it as the task’s draft; pass --file <spec.yaml> to save your reviewed version instead. Publish it with qualia task publish after review.


List a task’s VLM drafts: each run’s id, state, model, credits, and error.

Terminal window
qualia task drafts <TASK_ID>
OptionDescription
--limit, -nPage size, 1–500 (default: 20)
--cursorPagination cursor
--jsonJSON output

List the datasets linked to a task, or with --episodes its episodes from every dataset. An episode with no link of its own reads its dataset’s link; the Link column says which. The global --workspace picks the workspace.

Terminal window
qualia task linked <TASK_ID>
qualia task linked <TASK_ID> --episodes -n 100
OptionDescription
--episodesList the linked episodes instead of datasets
--limit, -nPage size, 1–500 (default: 20)
--cursorPagination cursor
--jsonJSON output

Link one episode to a task. A link, not an edit: the episode’s label, revisions and versions stay as they are. --unlink removes the episode’s own link only if it is to this task, and the episode then reads its dataset’s link again. To link a whole upload, use qualia dataset link-task.

Terminal window
qualia task link <TASK_ID> --episode <EPISODE_NAME>
qualia task link <TASK_ID> --episode <EPISODE_ID> --dataset <DATASET_ID>
qualia task link <TASK_ID> --episode <EPISODE_NAME> --unlink
OptionDescription
--episode, -eEpisode id (with --dataset) or full name
--dataset, -dThe dataset an episode id is read through
--unlinkRemove the episode’s own link to this task
--jsonJSON output

Enable fast large-file transfer for a cloned Qualia dataset repo. Run it once inside the clone; it configures the Git filter and adds the tracked patterns to .gitattributes, after which large files sync chunk-by-chunk instead of moving whole.

Terminal window
git clone https://dev-api.qualiastudios.dev/git/<org>/<name>.git
cd <name>
qualia git install
OptionDescription
--pathPath to the cloned dataset repo (default .)

Tracked by default: *.safetensors, *.gguf, *.parquet, *.mp4, *.mcap, *.bag, *.npz, *.npy, *.pt, *.bin, *.tar, *.zip. Patterns already present in .gitattributes are left alone.

The clone’s origin must be the same endpoint the CLI is configured against — the filter refuses a repo whose remote points somewhere other than the configured base URL, so a repo cloned from one environment cannot be pushed to another by changing the URL.

Without an API key the filter cannot move data; qualia git install says so rather than failing later inside a git command.



Running work and what ended recently, as the dashboard’s Running page shows it: ingests, check runs, training jobs and pipeline runs. A status is named under its workspace (accounts/<A>/workspaces/<W>/statuses/<OPERATION>), or under the organization for the organization’s own work.

List running work and work that ended within --recent, most recently changed first. The default is the workspace the CLI acts in (--workspace, else your key’s own).

Terminal window
qualia status list
qualia status list --running
qualia status list --org --recent 7d --json
qualia status list <WORKSPACE_ID> --filter 'service = "pipeline" AND state != FAILED'
Argument / OptionDescription
PARENTWorkspace ID or resource name (default: the workspace the CLI acts in)
--orgThe whole organization: every workspace’s work and its own
--runningOnly work that is queued or running
--recentHow far back ended work goes: 90s, 30m, 24h, 7d (default 24h, max 90 days)
--filterAIP-160 filter on state, kind and service; OR binds tighter than AND
--limit, -nPage size, 1–500 (default 50)
--cursorPagination cursor printed by the previous page

Each line is the operation ID, kind, state, progress, target and last change, and cancellable when qualia status cancel can stop it. A key restricted to workspaces cannot read or cancel statuses.

Ask the service running the work to stop it. Needs jobs:write and a contributor role on the work’s workspace. The status turns CANCELLED a moment after the service accepts; ended work, or a kind that cannot be cancelled, is refused.

Terminal window
qualia status cancel <OPERATION_ID>
qualia status cancel accounts/<A>/workspaces/<W>/statuses/<OPERATION_ID> --json

Run a check over a dataset and read what it found. The default check is the VLM check (vlm): a model reads each episode against the Task it is linked to. Confident failures become issues; uncertain readings become notes. Issues are flags on episodes. A check never keeps, rejects or deletes an episode.

The VLM check costs credits. Run qualia check estimate first: it shows the price and starts nothing. A run never spends more than it reserved.

qualia check also reads the thresholds the episode rules judge against (ranges) and the reach check’s status and results (reach-status, reach-cancel, results).

qualia check speaks qualia.v1, so it needs your account (--account or QUALIA_ACCOUNT; see Authentication).

qualia check runs one check by its slug. To run several checks from the catalog in one go, use qualia dataset checks.

What a VLM check would read and reserve. Starts and charges nothing. It prints the credits, the episode count (and how many are left out because they are not linked to a published Task), the model it would use and every model offered. It also fails the way the run would, for example when no episode is linked to a published Task.

Terminal window
qualia check estimate <DATASET_UUID>
qualia check estimate <DATASET_UUID> --max-episodes 50 --max-cost 200
Argument / optionDescription
DATASETDataset id or full name (required)
--episode, -eCheck only this episode (repeatable)
--filterCheck only episodes matching this filter
--model, -mVLM model; one of the models estimate lists as offered
--max-episodesSample at most N episodes
--max-costCredit ceiling
--jsonJSON output

Pass the same --max-episodes and --max-cost to qualia check run to reserve the same amount.

Start a check over a dataset. Without --check it runs the VLM check. It prints the name of each run it started (one per upload of a merged dataset); --wait waits for each run to end and prints its result. --check reach presses Run solver on a dataset: set the robot first with qualia dataset setup, and follow the run with qualia check reach-status.

Terminal window
qualia check run <DATASET_UUID> --max-episodes 50 --max-cost 200 --wait
qualia check run <DATASET_UUID> --check reach
Argument / optionDescription
DATASETDataset id or full name (required)
--check, -cCheck slug (default vlm); - runs the dataset’s defaults
--episode, -eCheck only this episode (repeatable)
--filterCheck only episodes matching this filter
--model, -mVLM model; one of the models estimate lists as offered
--max-episodesSample at most N episodes
--max-costCredit ceiling
--wait, -wWait for each run to end; exits 1 if one failed
--jsonJSON output

Show where a run stands: its state, how many issues it raised and resolved, and for the VLM check the model, the episodes read and the pass, fail and uncertain counts.

Terminal window
qualia check status accounts/<ACCOUNT>/checks/vlm/runs/<RUN_ID>
Argument / optionDescription
RUNRun name, accounts/.../checks/.../runs/..., as run prints
--jsonJSON output

List check runs, newest first.

Terminal window
qualia check runs --dataset <DATASET_UUID>
qualia check runs --check vlm --state RUNNING
OptionDescription
--check, -cCheck slug; - for all (default -)
--dataset, -dOnly this dataset’s runs
--stateQUEUED, RUNNING, SUCCEEDED or FAILED
--limit, -nRows per page, 1-1000 (default 20)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

The issues and notes a check raised on a dataset, with the model’s reading: the episode, the verdict, the confidence, the moments in seconds it points at, and the text. For what catalog checks wrote per episode, passes included, use qualia dataset checks findings.

Terminal window
qualia check findings <DATASET_UUID>
qualia check findings <DATASET_UUID> --limit 100 --json
Argument / optionDescription
DATASETDataset id or full name (required)
--check, -cCheck slug (default vlm)
--filterMore issue filter, ANDed
--limit, -nRows per page, 1-1000 (default 20)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

One check: its kind, what it checks, the dataset kinds it runs on, and whether this deployment can run it. qualia check get vlm says whether the VLM check is set up here.

Terminal window
qualia check get
qualia check get reach --json
Argument / optionDescription
CHECKvlm, episode-rules, mixture or reach (default vlm)
--jsonJSON output

The reference ranges the episode rules judge against, in your workspace. Each range is one metric on one robot interface (or one robot): its quantiles and the fences an episode is judged against. An upload’s interface is its robotInterface.interfaceHash (SDK client.datasets.get).

Terminal window
qualia check ranges --interface-hash b3:<HEX>
qualia check ranges --metric duration_seconds --json
OptionDescription
--check, -cCheck slug (default episode-rules)
--interface-hashOnly this robot interface (b3:…)
--robotOnly ranges narrowed to this robot (id or name)
--metricOnly this metric
--filterMore range filter (interface_hash, robot, metric)
--limit, -nRows per page, 1-1000 (default 20)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

Where a dataset’s reach check (Run solver) stands: the robot, the settings a run would use now, the last run with how many takes it solved, and whether it is stale (the robot, model, placement or poses changed since). It reads only; nothing runs by itself. A dataset with no usable robot has no key, and a run would start nothing.

Terminal window
qualia check reach-status <DATASET_UUID>
Argument / optionDescription
DATASETDataset id or full name (required)
--jsonJSON output

Press Run solver with qualia check run <DATASET> --check reach or qualia dataset setup <DATASET> --run-solver.

Stop the Run solver press that is under way. Takes not yet sent to the solver are dropped and takes already solved keep their results: the next run answers them from storage and solves the rest. It prints the status after the cancel.

Terminal window
qualia check reach-cancel <DATASET_UUID>
Argument / optionDescription
DATASETDataset id or full name (required)
--jsonJSON output

What the reach check stored per take: for each handheld or egocentric take on the dataset’s target robot, its state (NOT_RUN where nothing is solved under the current key yet), how many stretches the robot cannot follow and the longest, in seconds.

Terminal window
qualia check results <DATASET_UUID>
qualia check results <DATASET_UUID> --state SUCCEEDED --json
Argument / optionDescription
DATASETDataset id or full name (required)
--check, -cCheck slug (default reach; only reach stores results)
--episode, -eOnly this episode
--statePENDING, SUCCEEDED, FAILED or NOT_RUN
--robotOnly results on this robot (id or name)
--filterMore result filter, e.g. reach.longest_seconds > 1
--limit, -nRows per page, 1-1000 (default 20)
--cursorPagination cursor, as the previous page printed
--jsonJSON output

The checks catalog on one dataset. Catalog checks are versioned checks with an id such as task.graph or task.criteria, grouped by category. qualia dataset checks run runs a selection of them as one run; qualia dataset checks findings reads what they found.

Terminal window
qualia dataset checks list <DATASET_UUID>
qualia dataset checks run <DATASET_UUID> --category heuristic --validate-only
qualia dataset checks run <DATASET_UUID> --all --max-cost 200 --wait
qualia dataset checks findings <DATASET_UUID> --verdict FAIL

list shows every catalog check by category: whether it can run on this dataset (or why not) and its last result.

run runs the union of --check, --category and --all. Name at least one. A run reads one kind of check: the kind --check names, else VLM when a VLM check can run here, else the heuristics. It lists the checks it leaves out, with why, but not graph.observe and graph.evaluate: they run only inside qualia check run. A run needs --max-cost covering its bound: see the bound first with --validate-only, which starts nothing.

Option (run)Description
DATASETDataset id or full name (required)
--check, -cA catalog check id, e.g. task.graph (repeatable)
--categoryEvery runnable check of this category (repeatable)
--allEvery catalog check that can run here
--episode, -eCheck only this episode (repeatable)
--filterCheck only episodes matching this filter
--model, -mVLM model for the VLM checks in the selection
--max-episodesSample at most N episodes
--max-costCredit ceiling; required unless --validate-only
--validate-onlyResolve the selection and its bound; start nothing
--wait, -wWait for the run to end; exits 1 if it failed
--jsonJSON output

What catalog checks found on a dataset, newest first: per check, episode and finding, the verdict (PASS, FAIL or UNKNOWN), what it raised (ISSUE, NOTE or NONE) and a title.

Terminal window
qualia dataset checks findings <DATASET_UUID>
qualia dataset checks findings <DATASET_UUID> --check task.graph --verdict FAIL
qualia dataset checks findings <DATASET_UUID> --run accounts/<ACCOUNT>/checks/vlm/runs/<RUN_ID> --json
Argument / optionDescription
DATASETDataset id or full name (required)
--check, -cA catalog check id; - for all (default)
--runOnly this run’s findings (its full name)
--episode, -eOnly this episode
--verdictPASS, FAIL or UNKNOWN
--limit, -nRows per page, 1-1000 (default 20)
--cursorPagination cursor, as the previous page printed
--jsonJSON output