qualia-cli 0.1.2__tar.gz → 0.2.0rc2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/.gitignore +25 -3
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/PKG-INFO +40 -15
- qualia_cli-0.2.0rc2/README.md +80 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/pyproject.toml +12 -3
- qualia_cli-0.2.0rc2/qualia-cli.spec.md +40 -0
- qualia_cli-0.2.0rc2/src/qualia_cli/__init__.py +3 -0
- qualia_cli-0.2.0rc2/src/qualia_cli/client.py +25 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/auth.py +17 -10
- qualia_cli-0.2.0rc2/src/qualia_cli/commands/datasets.py +570 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/finetune.py +99 -17
- qualia_cli-0.2.0rc2/src/qualia_cli/commands/git.py +105 -0
- qualia_cli-0.2.0rc2/src/qualia_cli/config.py +140 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/main.py +20 -3
- qualia_cli-0.2.0rc2/tests/commands/__init__.py +0 -0
- qualia_cli-0.2.0rc2/tests/commands/test_datasets.py +452 -0
- qualia_cli-0.2.0rc2/tests/commands/test_finetune.py +58 -0
- qualia_cli-0.2.0rc2/tests/commands/test_git.py +47 -0
- qualia_cli-0.2.0rc2/tests/test_client.py +76 -0
- qualia_cli-0.2.0rc2/tests/test_config.py +107 -0
- qualia_cli-0.2.0rc2/tests/test_main.py +61 -0
- qualia_cli-0.2.0rc2/tests/test_sdk_floor.py +85 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/uv.lock +54 -16
- qualia_cli-0.1.2/README.md +0 -56
- qualia_cli-0.1.2/src/qualia_cli/__init__.py +0 -3
- qualia_cli-0.1.2/src/qualia_cli/client.py +0 -29
- qualia_cli-0.1.2/src/qualia_cli/commands/datasets.py +0 -85
- qualia_cli-0.1.2/src/qualia_cli/config.py +0 -63
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/__init__.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/credits.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/instances.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/models.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/commands/projects.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/src/qualia_cli/output.py +0 -0
- {qualia_cli-0.1.2 → qualia_cli-0.2.0rc2}/tests/__init__.py +0 -0
|
@@ -17,6 +17,8 @@ wheels/
|
|
|
17
17
|
.coverage
|
|
18
18
|
.coverage.*
|
|
19
19
|
htmlcov/
|
|
20
|
+
# Non-secret GitLab job receipts collected by `artifacts:` declarations.
|
|
21
|
+
/artifacts/
|
|
20
22
|
|
|
21
23
|
# virtual envs
|
|
22
24
|
.venv
|
|
@@ -46,7 +48,6 @@ easytier.log
|
|
|
46
48
|
reset.sql
|
|
47
49
|
|
|
48
50
|
# generated docs
|
|
49
|
-
ui/docs/src/assets/openapi.json
|
|
50
51
|
|
|
51
52
|
# nix
|
|
52
53
|
.direnv
|
|
@@ -58,7 +59,11 @@ result
|
|
|
58
59
|
|
|
59
60
|
# Windows
|
|
60
61
|
nul
|
|
61
|
-
|
|
62
|
+
|
|
63
|
+
# local upstream lerobot checkout (for debugging / vendor comparisons);
|
|
64
|
+
# our ported pipeline_lib_train_lerobot lives at api/pipeline/lib/train/lerobot/
|
|
65
|
+
# and must NOT be ignored.
|
|
66
|
+
/lerobot
|
|
62
67
|
|
|
63
68
|
# inference setup.sh artifact
|
|
64
69
|
inference/inference/examples/sim/openpi
|
|
@@ -89,8 +94,25 @@ dev_access_token.txt
|
|
|
89
94
|
.ripgreprc
|
|
90
95
|
.zprofile
|
|
91
96
|
.zshrc
|
|
97
|
+
.claude/scheduled_tasks.lock
|
|
92
98
|
/HEAD
|
|
93
99
|
/config
|
|
94
100
|
/hooks
|
|
95
101
|
/objects
|
|
96
|
-
/refs
|
|
102
|
+
/refs
|
|
103
|
+
|
|
104
|
+
# test data etc
|
|
105
|
+
api/qds/benchmarks/*
|
|
106
|
+
# Bench run artifacts. `benchmarks/` above never covered `bench/results/`, which
|
|
107
|
+
# is where the harness actually writes, so 6k lines of logs rode into a commit.
|
|
108
|
+
api/qds/bench/results/
|
|
109
|
+
api/qds/bench/RESULTS.md
|
|
110
|
+
api/qds/tests/validation/data/
|
|
111
|
+
api/qds/tests/quality_vlm_validation/data/
|
|
112
|
+
api/qds/tests/e2e/fixtures/data/
|
|
113
|
+
|
|
114
|
+
# Rust build artifacts
|
|
115
|
+
target/
|
|
116
|
+
**/target/
|
|
117
|
+
*.rlib
|
|
118
|
+
*.rmeta
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: qualia-cli
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: CLI for the Qualia
|
|
3
|
+
Version: 0.2.0rc2
|
|
4
|
+
Summary: CLI for the Qualia robotics data and VLA platform
|
|
5
5
|
Project-URL: Homepage, https://qualiastudios.dev
|
|
6
6
|
Project-URL: Documentation, https://docs.qualiastudios.dev
|
|
7
7
|
Author: Qualia Studios
|
|
@@ -16,14 +16,15 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Typing :: Typed
|
|
18
18
|
Requires-Python: >=3.10
|
|
19
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: click>=8.1.0
|
|
20
|
+
Requires-Dist: qualia-sdk>=0.7.0rc2
|
|
20
21
|
Requires-Dist: rich>=13.0.0
|
|
21
22
|
Requires-Dist: typer>=0.15.0
|
|
22
23
|
Description-Content-Type: text/markdown
|
|
23
24
|
|
|
24
25
|
# Qualia CLI
|
|
25
26
|
|
|
26
|
-
Terminal interface for the [Qualia](https://qualiastudios.dev) VLA
|
|
27
|
+
Terminal interface for the [Qualia](https://qualiastudios.dev) robotics data and VLA platform.
|
|
27
28
|
|
|
28
29
|
## Install
|
|
29
30
|
|
|
@@ -37,6 +38,23 @@ Or with [uv](https://docs.astral.sh/uv/):
|
|
|
37
38
|
uv tool install qualia-cli
|
|
38
39
|
```
|
|
39
40
|
|
|
41
|
+
### Pre-release builds
|
|
42
|
+
|
|
43
|
+
Deployments running ahead of the public release need the matching pre-release
|
|
44
|
+
wheel — the upload protocol is negotiated exactly, so the CLI and the endpoint
|
|
45
|
+
it talks to have to be the same generation. Pin it:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
pip install 'qualia-cli==0.2.0rc1'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
uv does not resolve a pre-release through a dependency, even one that names it,
|
|
52
|
+
so uv needs the flag as well as the pin:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
uv tool install --prerelease=allow 'qualia-cli==0.2.0rc1'
|
|
56
|
+
```
|
|
57
|
+
|
|
40
58
|
## Quick start
|
|
41
59
|
|
|
42
60
|
```sh
|
|
@@ -46,27 +64,34 @@ export QUALIA_API_KEY="your-api-key" # env var
|
|
|
46
64
|
qualia --token <KEY> <command> # inline, for CI/scripts
|
|
47
65
|
|
|
48
66
|
# List available models
|
|
49
|
-
qualia
|
|
67
|
+
qualia model list
|
|
50
68
|
|
|
51
69
|
# List GPU instances
|
|
52
|
-
qualia
|
|
70
|
+
qualia instance list
|
|
53
71
|
|
|
54
72
|
# Create a project
|
|
55
|
-
qualia
|
|
73
|
+
qualia project create "My Robot"
|
|
56
74
|
|
|
57
75
|
# Start a fine-tuning job
|
|
58
|
-
qualia
|
|
76
|
+
qualia job launch \
|
|
59
77
|
--project-id <id> \
|
|
60
78
|
--vla-type smolvla \
|
|
61
79
|
--model-id lerobot/smolvla_base \
|
|
62
|
-
--dataset-id
|
|
63
|
-
--dataset-last-modified "2025-01-15T10:00:00Z" \
|
|
64
|
-
--model-last-modified "2025-01-15T10:00:00Z" \
|
|
80
|
+
--dataset-version-id <DATASET_VERSION_UUID> \
|
|
65
81
|
--hours 2.0 \
|
|
66
82
|
--camera-mappings '{"cam_1": "observation.images.top"}'
|
|
67
83
|
|
|
68
84
|
# Check job status
|
|
69
|
-
qualia
|
|
85
|
+
qualia job get <job-id>
|
|
86
|
+
|
|
87
|
+
# Import an exact Hugging Face dataset commit. HF_TOKEN is read from the
|
|
88
|
+
# environment or the Hub's protected local credential store, never an argv flag.
|
|
89
|
+
export HF_TOKEN="..." # omit for public datasets
|
|
90
|
+
qualia dataset import-hf \
|
|
91
|
+
qualia-robotics/openarm-cube-in-box-v1 \
|
|
92
|
+
17c29c487d886878ddcb3c5649101b2860fbc047 \
|
|
93
|
+
openarm-cube-in-box \
|
|
94
|
+
--source-format lerobot_v3
|
|
70
95
|
```
|
|
71
96
|
|
|
72
97
|
## JSON output
|
|
@@ -74,6 +99,6 @@ qualia finetune get <job-id>
|
|
|
74
99
|
All commands support `--json` for machine-readable output:
|
|
75
100
|
|
|
76
101
|
```sh
|
|
77
|
-
qualia
|
|
78
|
-
qualia
|
|
102
|
+
qualia project list --json
|
|
103
|
+
qualia credit --json
|
|
79
104
|
```
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Qualia CLI
|
|
2
|
+
|
|
3
|
+
Terminal interface for the [Qualia](https://qualiastudios.dev) robotics data and VLA platform.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pip install qualia-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
uv tool install qualia-cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Pre-release builds
|
|
18
|
+
|
|
19
|
+
Deployments running ahead of the public release need the matching pre-release
|
|
20
|
+
wheel — the upload protocol is negotiated exactly, so the CLI and the endpoint
|
|
21
|
+
it talks to have to be the same generation. Pin it:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
pip install 'qualia-cli==0.2.0rc1'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
uv does not resolve a pre-release through a dependency, even one that names it,
|
|
28
|
+
so uv needs the flag as well as the pin:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
uv tool install --prerelease=allow 'qualia-cli==0.2.0rc1'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
# Authenticate (pick one)
|
|
38
|
+
qualia auth login # interactive, saves to config
|
|
39
|
+
export QUALIA_API_KEY="your-api-key" # env var
|
|
40
|
+
qualia --token <KEY> <command> # inline, for CI/scripts
|
|
41
|
+
|
|
42
|
+
# List available models
|
|
43
|
+
qualia model list
|
|
44
|
+
|
|
45
|
+
# List GPU instances
|
|
46
|
+
qualia instance list
|
|
47
|
+
|
|
48
|
+
# Create a project
|
|
49
|
+
qualia project create "My Robot"
|
|
50
|
+
|
|
51
|
+
# Start a fine-tuning job
|
|
52
|
+
qualia job launch \
|
|
53
|
+
--project-id <id> \
|
|
54
|
+
--vla-type smolvla \
|
|
55
|
+
--model-id lerobot/smolvla_base \
|
|
56
|
+
--dataset-version-id <DATASET_VERSION_UUID> \
|
|
57
|
+
--hours 2.0 \
|
|
58
|
+
--camera-mappings '{"cam_1": "observation.images.top"}'
|
|
59
|
+
|
|
60
|
+
# Check job status
|
|
61
|
+
qualia job get <job-id>
|
|
62
|
+
|
|
63
|
+
# Import an exact Hugging Face dataset commit. HF_TOKEN is read from the
|
|
64
|
+
# environment or the Hub's protected local credential store, never an argv flag.
|
|
65
|
+
export HF_TOKEN="..." # omit for public datasets
|
|
66
|
+
qualia dataset import-hf \
|
|
67
|
+
qualia-robotics/openarm-cube-in-box-v1 \
|
|
68
|
+
17c29c487d886878ddcb3c5649101b2860fbc047 \
|
|
69
|
+
openarm-cube-in-box \
|
|
70
|
+
--source-format lerobot_v3
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## JSON output
|
|
74
|
+
|
|
75
|
+
All commands support `--json` for machine-readable output:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
qualia project list --json
|
|
79
|
+
qualia credit --json
|
|
80
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "qualia-cli"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = "CLI for the Qualia
|
|
3
|
+
version = "0.2.0rc2"
|
|
4
|
+
description = "CLI for the Qualia robotics data and VLA platform"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
requires-python = ">=3.10"
|
|
@@ -20,7 +20,11 @@ classifiers = [
|
|
|
20
20
|
"Typing :: Typed",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"
|
|
23
|
+
"click>=8.1.0",
|
|
24
|
+
# 0.6.8 moved Hugging Face acquisition behind the server and 0.6.9 is the
|
|
25
|
+
# first wheel that speaks upload protocol v5. The gateway refuses older
|
|
26
|
+
# clients at `begin`, before any bytes move.
|
|
27
|
+
"qualia-sdk>=0.7.0rc2",
|
|
24
28
|
"typer>=0.15.0",
|
|
25
29
|
"rich>=13.0.0",
|
|
26
30
|
]
|
|
@@ -75,6 +79,11 @@ ignore = [
|
|
|
75
79
|
"E501", # line too long
|
|
76
80
|
]
|
|
77
81
|
|
|
82
|
+
[tool.ruff.lint.flake8-bugbear]
|
|
83
|
+
# Typer's Option/Argument defaults are the idiomatic way to declare CLI params;
|
|
84
|
+
# they're effectively immutable sentinels, so don't flag them under B008.
|
|
85
|
+
extend-immutable-calls = ["typer.Option", "typer.Argument"]
|
|
86
|
+
|
|
78
87
|
[tool.pytest.ini_options]
|
|
79
88
|
testpaths = ["tests"]
|
|
80
89
|
python_files = ["test_*.py"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Qualia CLI
|
|
3
|
+
category: product
|
|
4
|
+
surface: cli
|
|
5
|
+
capability: launch-finetune
|
|
6
|
+
maturity: review
|
|
7
|
+
verifies:
|
|
8
|
+
- sdk:contract
|
|
9
|
+
summary: The end-user Typer CLI wrapping the Qualia SDK.
|
|
10
|
+
owners: SDK / DX
|
|
11
|
+
updated: 2026-07-22
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
`qualia` is the end-user command-line interface — a Typer app over the Python SDK, giving the same
|
|
17
|
+
`launch-finetune` capability a terminal surface for scripting and CI. Collocated at `sdk/cli`. Not to
|
|
18
|
+
be confused with `qcore`, the internal developer CLI (see [Engineering →
|
|
19
|
+
qcore CLI is internal tooling]); `qualia` is the public, customer-facing one (QUA-633).
|
|
20
|
+
|
|
21
|
+
## Surface
|
|
22
|
+
|
|
23
|
+
The CLI mirrors the SDK's resource model: authenticate via `QUALIA_API_KEY`, then create and manage
|
|
24
|
+
finetunes, list the bounded QDS catalog, download a published tree, inspect adapter-pinned features
|
|
25
|
+
for an immutable `DatasetVersion`, list models/instances, and poll job status. Because it is a thin
|
|
26
|
+
wrapper, its behavior and conformance are inherited from the SDK and the public `/v1` Gateway.
|
|
27
|
+
|
|
28
|
+
## Conformance
|
|
29
|
+
|
|
30
|
+
Signal: `sdk:contract` (shared with the SDK). Production certification is pending the full contract
|
|
31
|
+
and deployed-path gates in the QDS execution plan. The active CLI accepts scoped API keys, uses the
|
|
32
|
+
canonical SDK resources, requires an immutable dataset-version UUID for training features and job
|
|
33
|
+
launches, and exposes the distinct `lerobot_v2_1`, `lerobot_v3`, and `mcap_ros2` catalog filters.
|
|
34
|
+
Historical QUA-795 and QUA-796 notes described an older route/auth surface and are not current
|
|
35
|
+
evidence.
|
|
36
|
+
|
|
37
|
+
## References
|
|
38
|
+
|
|
39
|
+
- `sdk/cli/`; QUA-633 (end-user CLI shipped)
|
|
40
|
+
- Wraps: [Qualia SDK](/specs/sdk/python/qualia-sdk/) → [Finetune API](/specs/api/gateway/finetune-api/)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Shared client factory."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from qualia import AuthenticationError, Qualia
|
|
6
|
+
|
|
7
|
+
from qualia_cli.config import load_config
|
|
8
|
+
from qualia_cli.output import print_error
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_client() -> Qualia:
|
|
12
|
+
from qualia_cli.main import _base_url_override, _token_override
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
cfg = load_config()
|
|
16
|
+
api_key = _token_override if _token_override is not None else cfg.api_key
|
|
17
|
+
base_url = _base_url_override if _base_url_override is not None else cfg.base_url
|
|
18
|
+
return Qualia(api_key=api_key, base_url=base_url)
|
|
19
|
+
except (AuthenticationError, OSError, UnicodeError, ValueError) as e:
|
|
20
|
+
print_error(str(e))
|
|
21
|
+
print_error(
|
|
22
|
+
"Set valid QUALIA_API_KEY/QUALIA_BASE_URL values or run: "
|
|
23
|
+
"qualia auth login --token <KEY>"
|
|
24
|
+
)
|
|
25
|
+
raise SystemExit(1) from e
|
|
@@ -4,7 +4,12 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import typer
|
|
6
6
|
|
|
7
|
-
from qualia_cli.config import
|
|
7
|
+
from qualia_cli.config import (
|
|
8
|
+
load_config,
|
|
9
|
+
save_config,
|
|
10
|
+
validate_api_key,
|
|
11
|
+
validate_base_url,
|
|
12
|
+
)
|
|
8
13
|
from qualia_cli.output import print_error
|
|
9
14
|
|
|
10
15
|
app = typer.Typer(help="Authentication.")
|
|
@@ -23,7 +28,7 @@ def login(
|
|
|
23
28
|
try:
|
|
24
29
|
path = save_config(api_key, base_url)
|
|
25
30
|
typer.echo(f"Config saved to {path}")
|
|
26
|
-
except OSError as e:
|
|
31
|
+
except (OSError, ValueError) as e:
|
|
27
32
|
print_error(f"Could not write config: {e}")
|
|
28
33
|
raise SystemExit(1) from e
|
|
29
34
|
|
|
@@ -31,13 +36,15 @@ def login(
|
|
|
31
36
|
@app.command("status")
|
|
32
37
|
def status() -> None:
|
|
33
38
|
"""Check current authentication config."""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
try:
|
|
40
|
+
cfg = load_config()
|
|
41
|
+
validate_api_key(cfg.api_key or "")
|
|
42
|
+
base_url = validate_base_url(cfg.base_url) if cfg.base_url is not None else None
|
|
43
|
+
except (OSError, UnicodeError, ValueError) as e:
|
|
44
|
+
typer.echo(f"Invalid authentication config: {e}")
|
|
45
|
+
raise SystemExit(1) from e
|
|
46
|
+
typer.echo("API key: configured")
|
|
47
|
+
if base_url:
|
|
48
|
+
typer.echo(f"Base URL: {base_url}")
|
|
42
49
|
else:
|
|
43
50
|
typer.echo("Base URL: https://api.qualiastudios.dev (default)")
|