Caasi v0.3.0 Data: dataset · sensor · vision

Data & Sensors

Generate simulation datasets as tracked runs, keep them inspectable and portable, discover the sensors attached to your machine, and verify the computer-vision stack — all without Caasi ever importing a single heavy library.

caasi dataset

SubcommandWhat it does
listList datasets under the datasets base directory.
generateGenerate a dataset from an experiment — the one launcher for simulation-collected and synthetic data.
inspectInspect a dataset.
convertConvert a dataset into a portable index (jsonl/csv).
validateValidate a dataset.
downloadDownload a dataset (Hugging Face, NGC or URL) as a tracked run.

Descriptions are the CLI's own — caasi dataset --help prints this list. For fetching existing datasets instead of generating them see dataset download below and its extended treatment in synthetic.html.

New in 0.3.0: the root synth group is gone

Synthetic-data generation is no longer a command group of its own — synth is a backend, resolved through the sdg catalog domain, and dataset generate is its canonical launcher. Every old caasi synth … verb has a dataset equivalent:

Up to 0.2.0Since 0.3.0
caasi synth generate CONFIGcaasi dataset generate CONFIG
caasi synth preview QUERYcaasi dataset inspect QUERY
caasi synth validate QUERYcaasi dataset validate QUERY
caasi synth statuscaasi dataset list for the datasets it produced; caasi doctor --component data for the Replicator capabilities

The Replicator side of generation — the sdg capabilities, the synthetic tree layout and the SDG validation rules — is documented in synthetic.html.

What a dataset is

A dataset is a directory with a metadata.json plus any of the known data subdirectories:

wave-100-20260905-170412/
├── metadata.json
├── episodes/       # per-episode recordings
├── observations/   # agent observations
├── actions/
├── rewards/
├── poses/
├── images/         # RGB frames (--record-images)
├── depth/          # depth frames (--record-depth)
└── lidar/          # point clouds (--record-lidar)

Datasets are looked for in the project's datasets/ directory when you are inside a project, otherwise in paths.datasets (default ~/.caasi/datasets). Directory names follow <name-slug>-<YYYYmmdd-HHMMSS>.

The QUERY argument

inspect, convert and validate accept:

Unknown or ambiguous → Error: No dataset matching '<query>'. (exit 1).

caasi dataset list

caasi dataset list [--limit|-n N] [--json]

Every dataset under the base directory — the project's datasets/ when you are inside a project, else paths.datasets — newest first. A directory counts only when it holds a metadata.json; --limit defaults to 20 (and --limit 0 means “none”).

shellcaasi dataset list
Name                       Status       Files  Size
wave-100-20260905-170412   generating   1301   81.3 KiB
aloha-sim-20260905-180233  downloading  13     877 B
caasi dataset list --limit 1 --json | jq '.datasets[0]'
{
  "name": "wave-100-20260905-170412",
  "path": "/home/you/.caasi/datasets/wave-100-20260905-170412",
  "status": "generating",
  "source": null,
  "files": 1301,
  "size": 83269
}

Status and source come straight from metadata.json (unknown / null when absent), while Files and Size are counted on disk, recursively and including metadata.json — the same scan inspect reports. The JSON payload is {"base": "<datasets dir>", "datasets": [{"name", "path", "status", "source", "files", "size"}]}.

An empty base directory is data, not an error — No datasets found. in yellow, exit 0 ({"base": …, "datasets": []} in JSON):

shellcaasi dataset list
No datasets found.
caasi dataset list --json
{
  "base": "/home/you/.caasi/datasets",
  "datasets": []
}

caasi dataset generate

caasi dataset generate CONFIG_PATH [--episodes N] [--workers N] [--record-images]
            [--record-depth] [--record-lidar] [--name NAME] [--dry-run] [-- SCRIPT_ARGS…]

Since 0.3.0 this is the canonical launcher for all dataset generation, synthetic data included. Which generator actually runs is a backend question, resolved through the catalog (the sdg domain for Isaac Sim Replicator) instead of a separate command group: point generate at an experiment whose script drives Replicator and you get a synthetic dataset, point it at a collector script and you get a simulation-collected one — same options, same metadata.json, same tracked run. The Replicator specifics (the gate, the synthetic tree and its extra validation rules) are in synthetic.html.

ParameterKindTypeDefaultDescription
CONFIG_PATHargumentpathrequiredThe experiment YAML whose script collects the data.
--episodesoptionint—→ script arg --episodes N.
--workersoptionint—→ script arg --workers N.
--record-imagesoptionflagoff→ script arg --record-images.
--record-depthoptionflagoff→ script arg --record-depth.
--record-lidaroptionflagoff→ script arg --record-lidar.
--nameoptionstrexperiment nameDataset name (dir name gets a timestamp suffix).
--dry-runoptionflagoffShow the command; create nothing.

What happens on launch:

  1. The dataset directory is created and metadata.json is written with status: "generating", the experiment path, backend, episodes/workers, the record flags and the linked run_id.
  2. The script receives --dataset-dir <dir> and the environment variable CAASI_DATASET_DIR — write your collected files there.
  3. A detached run (kind: dataset) is started exactly like sim run.
shellcaasi dataset generate experiments/collect.yaml --episodes 100 --record-images
Dataset generation started: /home/you/.caasi/datasets/wave-100-20260905-170412
Run: 20260905-170412-wave — follow it with 'caasi logs 20260905-170412-wave -f'

caasi dataset inspect

caasi dataset inspect QUERY [--json]

Shows the metadata, the linked run's live status, and what is actually on disk (file counts per subdirectory, total size):

shellcaasi dataset inspect latest
wave-100-20260905-170412
  /home/you/.caasi/datasets/wave-100-20260905-170412
  name       wave-100
  created    2026-09-05T17:04:12+08:00
  experiment /home/you/demo/experiments/collect.yaml
  backend    sim
  episodes   100
  record     images=True depth=False lidar=False
  status     generating
  Run: 20260905-170412-wave (succeeded)
Directory  Files
episodes     100
images      1200
caasi dataset inspect latest --json | jq '.run'
{ "id": "20260905-170412-wave", "status": "succeeded" }

JSON payload: {"path", "metadata", "contents": {"files", "size", "dirs"}, "run"}; run is null when unlinked, or {"id", "status": "unknown"} if the run was deleted.

caasi dataset convert

caasi dataset convert QUERY [--to jsonl|csv] [--output PATH]

Builds a portable index of every file in the dataset (relative path + size, excluding metadata.json and previous indexes) — handy for training pipelines that just need a file list:

shellcaasi dataset convert latest --to csv
Index written to /home/you/.caasi/datasets/wave-100-20260905-170412/index.csv (1300 file(s)).
head -3 /home/you/.caasi/datasets/wave-100-20260905-170412/index.csv
path,size
episodes/ep_000.json,4213
images/frame_00000.png,184322

Defaults: --to jsonl (one {"path": …, "size": …} object per line), output <dataset>/index.<fmt>. Unknown format → Error: unknown index format '…' (expected one of jsonl, csv) (exit 1).

caasi dataset validate

caasi dataset validate QUERY [--json]

Structural validation:

shellcaasi dataset validate latest --json
{
  "path": "/home/you/.caasi/datasets/wave-100-20260905-170412",
  "valid": false,
  "issues": ["metadata declares 100 episode(s) but episodes/ contains 97"]
}
exit code: 1

Exit 0 valid / 1 any issue — in both human and JSON mode. For a synthetic (Replicator) dataset the same command also applies the SDG rules — rgb/ against the declared episode count, and depth/, segmentation/, bounding_boxes/ against rgb/; see synthetic.html.

caasi dataset download

caasi dataset download REF [--backend hf|ngc|url] [--name NAME] [--dry-run] [-- EXTRA…]

Fetches a dataset that already exists instead of generating one. The backend is auto-detected from the reference's scheme; --backend forces one (and then a bare org/name is accepted too). Caasi resolves an upstream downloader and delegates the whole transfer to it — no HTTP client, no SDK, nothing imported:

ReferenceBackendTool (first found on PATH)Command built
hf://org/namehfhf, then huggingface-cli<tool> download org/name [EXTRA…] --local-dir <dataset-dir>
ngc://org/name:versionngcngc<tool> registry dataset download-version org/name:version [EXTRA…] --dest <dataset-dir>
http(s)://…/fileurlcurl, then wgetcurl -L [EXTRA…] -o <dataset-dir>/file <url> (wget [EXTRA…] -O …)

The destination is a fresh dataset directory named --name or the source's last path segment, plus the usual timestamp suffix. The transfer starts as a detached run — kind: dataset, backend = the detected backend, extra: {source, dataset} in the manifest — and metadata.json is written at launch with status: "downloading" and the run_id, so caasi run status and caasi logs follow it like any other run:

shellcaasi dataset download hf://lerobot/aloha_sim --dry-run
Dry run — nothing was started:
  command: hf download lerobot/aloha_sim --local-dir /home/you/.caasi/datasets/aloha-sim-20260905-180233
  dest:    /home/you/.caasi/datasets/aloha-sim-20260905-180233
caasi dataset download https://example.com/data.tar.gz --dry-run
Dry run — nothing was started:
  command: /usr/bin/curl -L -o /home/you/.caasi/datasets/data-tar-gz-20260905-180411/data.tar.gz https://example.com/data.tar.gz
  dest:    /home/you/.caasi/datasets/data-tar-gz-20260905-180411
caasi dataset download https://example.com/data.tar.gz
Dataset download started: /home/you/.caasi/datasets/data-tar-gz-20260905-180512
  Run: 20260905-180512-data-tar-gz — follow it with 'caasi logs 20260905-180512-data-tar-gz -f'

Unrecognized flags pass straight through to the tool, between the source and the destination flags — --revision main yields hf download lerobot/aloha_sim --revision main --local-dir <dataset-dir>. A --dry-run needs no downloader installed (the command is printed with the backend's default tool name) and leaves no directory behind.

Both refusals happen before anything is created, and both exit 1:

shell# neither hf nor huggingface-cli on PATH
caasi dataset download hf://lerobot/aloha_sim
Error: No download tool found for backend 'hf'.
exit code: 1
caasi dataset download ftp://example.com/x
Error: Cannot detect a download backend for 'ftp://example.com/x' (use hf://, ngc://, http(s):// or --backend hf|ngc|url).
exit code: 1

Once the files land the directory is an ordinary dataset: dataset list shows it with its source and status, and inspect / convert / validate all work on it. Cache behaviour and the Replicator-side workflow are covered in synthetic.html.

caasi sensor

Discovers sensors by scanning /dev, sysfs and pip metadata — vendor SDKs are never imported. Five sensors are known:

NameKindDetected viaIf missing
camerasvideo4linux/dev/video* + /sys/class/video4linux/*/namehint: v4l2-ctl --list-devices
realsensedepth-camerapip package pyrealsense2hint: pip install pyrealsense2
zeddepth-cameradirectory /usr/local/zedhint: install the ZED SDK
lidarserial/dev/ttyUSB*, /dev/ttyACM*hint: connection/udev rules
isaacsimsimulationthe usual Isaac Sim detection chainhint: caasi setup isaacsim

caasi sensor list

caasi sensor list [--json]
shellcaasi sensor list
Sensor     Kind          Status        Detail
cameras    video4linux   detected      1 device(s)
realsense  depth-camera  not detected  pyrealsense2 not installed
zed        depth-camera  not detected  ZED SDK not found
lidar      serial        not detected  0 serial device(s)
isaacsim   simulation    detected      Isaac Sim 6.0 at /opt/isaac-sim-6.0
caasi sensor list --json | jq '.[0]'
{ "name": "cameras", "kind": "video4linux", "detected": true,
  "detail": "1 device(s)", "devices": ["/dev/video0 (Integrated Webcam)"],
  "hint": "check the device with 'v4l2-ctl --list-devices'" }

Always exits 0 — missing sensors are data, not errors.

caasi sensor inspect

caasi sensor inspect NAME [--json]

Detail for one sensor (devices list, hint). Exit 0 even when not detected; 1 for an unknown name (Error: Unknown sensor '<n>'. Valid: cameras, realsense, zed, lidar, isaacsim).

caasi sensor test

caasi sensor test NAME [--json]

Gating version of inspect: exits 0 when the sensor is detected, 1 when not — for scripts like:

shellcaasi sensor test cameras || echo "no camera — using sim sensors"
Sensor 'cameras' is available: 1 device(s)
caasi sensor test lidar --json
{ "name": "lidar", "ok": false, "detail": "0 serial device(s)" }
exit code: 1

caasi vision

Diagnoses the computer-vision Python stack. “Installed” means pip metadata is present — the package is never imported by status/inspect. Six components, each mapped to its import module and candidate distributions:

ComponentModuleDistributions checked (in order)
opencvcv2opencv-python, opencv-python-headless, opencv-contrib-python
open3dopen3dopen3d, open3d-cpu
onnxruntimeonnxruntimeonnxruntime-gpu, onnxruntime
tensorrttensorrttensorrt
pytorchtorchtorch
pillowPILpillow

caasi vision status

caasi vision status [--json]
shellcaasi vision status
Component    Status     Version  Module
opencv       installed  4.10.0   cv2
open3d       installed  0.18.0   open3d
onnxruntime  installed  1.19.0   onnxruntime
tensorrt     missing    —        tensorrt
pytorch      installed  2.4.0    torch
pillow       installed  10.4.0   PIL
Install missing components with 'pip install <package>'.

JSON: array of {"name", "installed", "version", "module"}. Always exits 0.

caasi vision inspect

caasi vision inspect COMPONENT [--json]

One component in detail, with an install hint when missing. Exit 0 for known names (installed or not); 1 for unknown names.

caasi vision test

caasi vision test [COMPONENT…] [--python PATH] [--json]

The real proof: imports each component — in a subprocess, with a 30-second timeout, optionally using a different interpreter (--python, default: the CLI's own). This catches broken installs that pip metadata alone would happily report as fine.

shellcaasi vision test
opencv: 4.10.0
open3d: 0.18.0
onnxruntime: 1.19.0
tensorrt: missing
pytorch: 2.4.0
pillow: 10.4.0
exit code: 1
caasi vision test opencv pytorch --python /opt/IsaacLab/_isaac_sim/python.sh --json
[ { "name": "opencv", "ok": true, "detail": "4.10.0" },
  { "name": "pytorch", "ok": true, "detail": "2.4.0" } ]

Exit 0 only if every tested component imports successfully; 1 if any fails, times out, or the name is unknown. No arguments = all six.