Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

qualia-cli — terminal client for the Qualia robotics data and VLA platform

Status: beta source candidate (0.3.0rc4) · Distribution: PyPI, qualia-cli

Wraps the public Qualia API: authenticate once, then manage projects, import datasets, launch fine-tuning jobs and follow their progress from a shell. Every command takes --json, so the same surface works interactively and in CI.

The CLI and the endpoint it talks to negotiate the upload protocol exactly, so a deployment running ahead of the public release needs the matching pre-release wheel. See Install below.

Install

pip install qualia-cli

Or with uv:

uv tool install qualia-cli

Pre-release builds

Pin the wheel that matches the endpoint's generation. This source candidate is 0.3.0rc4 and requires qualia-sdk>=0.8.0rc4 for workspace-bound saved upload destinations. Use these commands after the candidates are published and your deployment supports the merged-upload lifecycle; otherwise select the matching published version.

pip install 'qualia-cli==0.3.0rc4'

uv does not resolve a pre-release through a dependency, even one that names it, so uv needs the flag as well as the pin:

uv tool install --prerelease=allow 'qualia-cli==0.3.0rc4'

Usage

# Authenticate (pick one)
qualia auth login                        # interactive, saves to config
export QUALIA_API_KEY="your-api-key"     # env var
qualia --token <KEY> <command>           # inline, for CI/scripts

# List available models
qualia model list

# List GPU instances
qualia instance list

# Create a project
qualia project create "My Robot"

# Start a fine-tuning job
qualia job launch \
  --project-id <id> \
  --vla-type pi05 \
  --model-id lerobot/pi05_base \
  --dataset-version-id <DATASET_VERSION_UUID> \
  --hours 2.0 \
  --camera-mappings '{"cam_1": "observation.images.top"}'

# Check job status (a pipeline with map nodes also shows each map's item
# progress and its map ID)
qualia job get <job-id>
# A failed job also prints who caused it (your side or ours), what, why, and its credits

# Page a map's items: one row per attempt, filtered by state if you like
qualia job items <job-id> <map-id> --status failed --limit 50 --offset 0

# Upload a recorded MCAP session; a session no bag can derive is refused
# before upload unless you pass --allow-underivable
qualia dataset upload ./session dk1-kitchen --source-format mcap_ros2
# exits 0 published/degraded, 1 nothing uploaded, 3 stored but no episode derived

# A teleop arm needs no config when its state is a JointState topic named
# joint_state(s) and its action is a JointTrajectory topic, or a JointState or
# MultiArray topic named cmd, command or action. In <session>/meta/ingest.toml,
# declare [actions] alone when a topic named like a command is operator input
# (a joystick), and both [state] and [actions] when a second JointState topic
# (a leader arm) would be read as state, or the rig publishes poses and has no
# JointState:
#   schema = 1
#   [state]
#   topics = ["/controller/left/pose", "/controller/right/pose"]
#   [actions]
#   topics = []   # no action column
# Fields are carried as recorded, with no rotation conversion. [clock] takes
# row_clock_topic or fixed_hz, not both.
# Guide: https://docs.qualiastudios.dev/global/guides/data-collection
# A successful upload prints the topics that fed state and action, and says
# "action: none (no action column)" when there is none. --quiet still prints them.

# LeRobot trees are checked before upload too. A structural problem the server
# always refuses (bad meta/info.json, codebase_version not matching
# --source-format, no parquet under data/, v2.1 without episodes.jsonl or
# tasks.jsonl) exits 1 with nothing uploaded; --allow-underivable cannot
# override it. A missing video only warns, naming the episode and camera; the
# upload continues and that episode will be flagged (you should probably
# exclude it).
qualia dataset upload ./my-recording my-dataset --source-format lerobot_v3

# Save a default merged-dataset destination for uploads in this local config.
# It is bound to this API host, account, and workspace; changing it affects
# future upload intents, not uploads already in flight.
qualia dataset destination set accounts/<account-uuid>/datasets/<merged-uuid>
qualia dataset destination show
qualia dataset destination clear

# Override that default for one upload, or keep one upload standalone.
qualia dataset upload ./week-2 week-2 --source-format lerobot_v3 \
  --merge-target accounts/<account-uuid>/datasets/<merged-uuid>
qualia dataset upload ./calibration calibration --source-format lerobot_v3 --standalone

# Workspace selection is the gateway's X-Qualia-Workspace context. An explicit
# selection overrides the workspace bound to the saved destination; a mismatch
# leaves this upload standalone instead of sending it into another workspace.
qualia --workspace <project-uuid> dataset upload ./week-3 week-3 \
  --source-format lerobot_v3
export QUALIA_WORKSPACE=<project-uuid>  # alternatively, select it for this shell

# If append needs action, the upload remains published and the command prints
# its dataset ID and reason. A retry after an explicit revert keeps that intent
# reverted; it never silently appends again.

# List your uploads; Verdict is published | degraded | underivable. With your account set
# (see Tasks below) it reads qualia.v1 and --json prints qualia.v1 Datasets (reason:
# verdict_reason); without one it reads the older route (reason: qds.verdict_reason).
qualia dataset list

# Filter the account-scoped list by any canonical method tag.
qualia dataset list --method umi --method teleop

# Replace the canonical method-tag set on an upload or merged dataset. A
# merged dataset writes the same set to every upload it holds; --clear records
# an explicit Unknown rather than leaving tags unset.
qualia dataset methods <dataset-uuid> --method umi --method teleop
qualia dataset methods <dataset-uuid> --clear

# Cut episodes into child episodes at their markers, or, where the recorder
# marked nothing, at instants (seconds from the start of the recording, the
# same instants in each named episode). --dry-run plans without writing;
# `qualia dataset unsplit` undoes it. A request cuts at markers or at
# instants, not both.
qualia dataset split <episode> -d <dataset> --cut-at success --dry-run
qualia dataset split <episode> -d <dataset> --at 12.5 --at 31 --dry-run

# Import an exact Hugging Face dataset commit. HF_TOKEN is read from the
# environment or the Hub's protected local credential store, never an argv flag.
export HF_TOKEN="..."  # omit for public datasets
qualia dataset import-hf \
  qualia-robotics/openarm-cube-in-box-v1 \
  17c29c487d886878ddcb3c5649101b2860fbc047 \
  openarm-cube-in-box \
  --source-format lerobot_v3

Tasks

Tasks say what a robot should do and how success shows, as five pieces of prose: description, scene, steps (one per line), success and failure. They live under your account: pass --account <UUID>, set QUALIA_ACCOUNT, or save it with qualia auth login --account <UUID>.

qualia task create --name "Restock shelf" -d "Move every box from the tray to the shelf"
qualia task edit <task-id> --steps $'Pick a box from the tray\nPlace it upright on the shelf' \
  --success "The tray is empty and every box stands upright"
                                               # just those fields; "" clears one

# Or author the five fields as a file, as `qualia task get <id> --json` prints
# a task (displayName, etag, draft) or as a bare spec:
cat > shelf.yaml <<'EOF'
description: Move every box from the tray to the shelf
scene: A tray of six boxes beside a two-level wire shelf
steps: |
  Pick a box from the tray
  Place it upright on the shelf
success: The tray is empty and every box stands upright
failure: A box falls over or drops to the floor
EOF
qualia task edit <task-id> shelf.yaml          # replaces the whole draft

# A spec file may also hold an optional procedure: the task as a state machine of
# steps and transitions, checked when the task is published.
cat >> shelf.yaml <<'EOF'
procedure:
  steps:
    - {id: start, kind: START, description: Boxes in the tray}
    - {id: place, description: Place a box upright on the shelf, min_count: 6, max_count: 6}
    - {id: shelved, kind: SUCCESS, description: All boxes shelved}
    - {id: fallen, kind: FAILURE, description: A box fell over}
  transitions:
    - {source: start, target: place}
    - {source: place, target: shelved}
    - {source: place, target: fallen}
EOF
qualia task edit <task-id> shelf.yaml

qualia task get <task-id>                      # each field under its heading, then the procedure
qualia task publish <task-id> -m "first cut"   # needs a description and a success
qualia task revisions <task-id>
qualia task get <task-id> --revision 1
qualia task list
qualia task delete <task-id> [--force]         # account owners only

Link recorded data to the task it was recorded against (CLI 0.3.0rc3). The label stays the text training reads; a link changes no revision or version, and deleting the task unlinks.

qualia dataset link-task <upload-id> <task-id>             # --unlink removes it
qualia dataset assign-task -d <upload-id> --task <task-id> --filter 'state = KEPT'
                                               # links and labels them with the task's name
qualia dataset assign-task <episode-id>... -d <upload-id> --label "restock shelf"
                                               # a label alone leaves links as they are

Checks

Run a check over a dataset and read its findings. The VLM check reads each episode against its linked, published task; estimate says what a run would reserve without starting or charging anything.

qualia check estimate <dataset>                  # credits, episodes, the model and those offered
qualia check run <dataset> --model <model> --wait  # --check episode-rules|mixture|reach; - for defaults
qualia check status <run-name>                   # QUEUED, RUNNING, SUCCEEDED or FAILED, with counts
qualia check runs --check vlm -d <dataset> --state FAILED
qualia check findings <dataset>                  # issues and notes, with verdict, confidence and moments

JSON output

All commands support --json for machine-readable output:

qualia project list --json
qualia credit --json

API

The CLI is a client for the public Qualia API. Request and response shapes for every command are in the API reference: https://docs.qualiastudios.dev

Working in the repo instead? sdk/cli/qualia-cli.spec.md carries the same contract, and the gateway generates the OpenAPI spec it is drawn from. Neither ships in the wheel.

License

MIT, Qualia Studios.

A saved merge destination is used only with a known matching account, normalized API host and workspace. An environment API key alone does not confirm the saved account; supply the matching account configuration explicitly. Explicit --merge-target and --standalone retain their per-call meaning.

Metadata

Release files for qualia-cli 0.3.0rc4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qualia-cli 0.3.0rc4
File Size Uploaded Provenance
qualia_cli-0.3.0rc4.tar.gz 123.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for qualia-cli 0.3.0rc4
File Interpreter ABI Platform
qualia_cli-0.3.0rc4-py3-none-any.whl Python 3 none any Details

Total release size: 170.4 kB

Release files / qualia_cli-0.3.0rc4.tar.gz

Download URL qualia_cli-0.3.0rc4.tar.gz
Size 123.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6d2cf6cf07f543b4d695d1cbfb93718b92db7b2eb4964ceaf6bbf3592cbcad5e
BLAKE2b-256 checksum
How to use checksums
e4fad124f2f9d87eb7e924fc680f3aadac1f8f1f3fa0d468fb62774d2b6a6d12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.0","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / qualia_cli-0.3.0rc4-py3-none-any.whl

Download URL qualia_cli-0.3.0rc4-py3-none-any.whl
Size 46.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8dcd09768d4f358625bb84e6d05f1d2cec143d28bc3bfac06aee5c5cf0e4bc6b
BLAKE2b-256 checksum
How to use checksums
14f545a82a2311a258d193f6f50b6d58579242b4d8294dc355123c0f8f99c776
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Alpine Linux","version":"3.23.0","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for qualia-cli 0.3.0rc4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page