Metadata-Version: 2.5
Name: qualia-cli
Version: 0.3.0rc2
Summary: CLI for the Qualia robotics data and VLA platform
Project-URL: Homepage, https://qualiastudios.dev
Project-URL: Documentation, https://docs.qualiastudios.dev
Author: Qualia Studios
License-Expression: MIT
Keywords: cli,fine-tuning,qualia,robotics,vla
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: click>=8.1.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: qualia-sdk>=0.8.0rc2
Requires-Dist: rich>=13.0.0
Requires-Dist: typer>=0.15.0
Description-Content-Type: text/markdown

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

**Status:** beta (0.3.0rc2) · **Published:** 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

```sh
pip install qualia-cli
```

Or with [uv](https://docs.astral.sh/uv/):

```sh
uv tool install qualia-cli
```

### Pre-release builds

Pin the wheel that matches the endpoint's generation. The current release candidate is
`0.3.0rc2`; if your deployment is on a different one, swap it in.

```sh
pip install 'qualia-cli==0.3.0rc2'
```

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:

```sh
uv tool install --prerelease=allow 'qualia-cli==0.3.0rc2'
```

## Usage

```sh
# 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
qualia job get <job-id>
# A failed job also prints who caused it (your side or ours), what, why, and its credits

# 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

# 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>`.

```sh
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
```

### JSON output

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

```sh
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.
