Nuuduu
Nuuduu is a Python SDK and CLI that gets robotics training data from the Nuuduu Atlas library onto your machine as a PyTorch-ready dataset — and automatically requests new data collection when the library does not have enough.
| Step | What it does |
|---|---|
| Search | Find episodes in the Atlas library by task description and country |
| Bundle | Package matching episodes into a training dataset (LeRobot by default) |
| Sync | Download ready bundles to your local dataset directory |
| Request | Order new episodes to be collected when the library is short |
Use what Atlas already has, or combine --min-episodes on bundle to bundle available episodes and request the rest in one command.
| URL | |
|---|---|
| Atlas web app | https://nuuduu.ai/atlas |
| Atlas API (default) | https://nuuduu.ai/api/atlas |
| Nuuduu Ego profile spec | https://bitbucket.org/nuuduu/nuuduu-ego-spec/ |
The CLI talks to the API at nuuduu.ai. Manage your account and payment method in the Atlas web app.
Source repository: bitbucket.org/nuuduu/nuuduu
Installation
# Library only
pip install nuuduu
# Library + CLI command (quote brackets so the shell does not treat them as globs)
pip install 'nuuduu[cli]'
Development install:
git clone git@bitbucket.org:nuuduu/nuuduu.git
cd nuuduu
pip install -e '.[dev]'
pytest
How it works
Atlas library Your machine
───────────── ────────────
search ──→ find episodes
bundle ──→ package as LeRobot / MCAP / HEVC dataset
sync ──→ download ──→ PyTorch / LeRobot training dataset
request ──→ collect new episodes (when library is short)
↑
└── triggered automatically by bundle --min-episodes
Typical path — library has enough data:
nuuduu search --text "shirt folding" # explore + see total price
nuuduu bundle --text "shirt folding" # purchase + package
nuuduu sync # download locally
When you need more than the library has:
nuuduu bundle --text "shirt folding" --country fi,ee --min-episodes 10000
# bundles 6 000 available episodes, requests collection of the remaining 4 000
nuuduu sync # run again as bundles become ready
The default output format is LeRobot v3.0, ready for PyTorch training via LeRobot or your own data loader.
Quick start (CLI)
nuuduu auth login
# 1. Search Atlas
nuuduu search --text "fold a t-shirt"
# 2. Get 1,000 episodes bundled as LeRobot v3.0
# Existing episodes are used immediately and any shortfall is collected.
nuuduu bundle \
--text "fold a t-shirt" \
--min-episodes 1000 \
--profile nuuduu
# 3. Download the dataset somewhere explicit
nuuduu sync --dataset-dir ~/nuuduu-atlas/datasets
# 4. Train with LeRobot
python -m lerobot.scripts.train \
--dataset.repo_id=local \
--dataset.root=~/nuuduu-atlas/datasets/lerobot/<download-uuid> \
...
Example output:
$ nuuduu auth login
✓ Logged in as researcher@acme.ai
$ nuuduu search --text "fold a t-shirt"
681 episodes found · $486.32 available now
$ nuuduu bundle --text "fold a t-shirt" --min-episodes 1000 --profile nuuduu
Available now: 681 To collect: 319
Estimated total: $742.00
Confirm purchase? [Y/n] y
✓ Bundle 7f3c2a91 created · LeRobot v3.0 · Nuuduu Ego
$ nuuduu sync --dataset-dir ~/nuuduu-atlas/datasets
✓ 681 episodes synced
~/nuuduu-atlas/datasets/lerobot/7f3c2a91
Need episodes that are not in the library yet? Use --min-episodes to bundle what's available and request collection of the rest, or request directly:
nuuduu bundle --text "shirt folding" --min-episodes 10000 --country fi,ee
nuuduu request --text "pick and place red blocks" --episodes 1000 --country fi,ee
Quick start (library)
from nuuduu import NuuduuAtlas
atlas = NuuduuAtlas.from_config()
# Search the Atlas library
episodes = atlas.search_episodes(text="shirt folding", country="fi,ee", limit=100)
print(f"Found {len(episodes)} episodes")
# Bundle available episodes; automatically request collection for any shortfall
bundle = atlas.bundle_episodes(
text="shirt folding",
country="fi,ee",
min_episodes=10000,
profile="nuuduu",
confirm_request=True,
)
print(f"{bundle.bundled_episodes} bundled, {bundle.requested_episodes} requested")
# Download ready bundles to a local PyTorch-ready dataset
result = atlas.sync(format="lerobot")
for item in result.synced:
print(item.path) # e.g. .../lerobot/<uuid>/
Authentication
Use the same email and password as your Atlas web app account. nuuduu auth login calls POST /api/atlas/login with type=api and creates a named API key (default name Nuuduu CLI; override with --name). The returned token is long-lived (unlike 24-hour web session tokens).
Credentials are stored at ~/.config/nuuduu/config.toml with 0600 permissions. The CLI refuses to read config files that are group- or world-readable.
| Method | Usage |
|---|---|
| Config file | api_token = "..." in ~/.config/nuuduu/config.toml |
| Environment | export NUUDUU_API_TOKEN="..." |
| Programmatic | NuuduuAtlas(token="...") |
nuuduu auth login # email + password → creates API key, saves token
nuuduu auth login --name "CI" # custom label for the API key in Atlas settings
nuuduu auth logout # clear saved token
nuuduu auth token set TOKEN # set token manually
nuuduu auth status # show masked token status
On HTTP 401, run nuuduu auth login again or set a valid API key from the Atlas web app.
Payment
When you confirm a bundle or collection request in the CLI, payment is charged automatically to the default payment method on your Atlas account. No browser step or extra checkout flow is required.
The only payment issues you may see:
| Situation | What to do |
|---|---|
| No payment method on file | Add a card at nuuduu.ai/atlas |
| Card declined or charge failed | Update your payment method in the Atlas web app and retry |
nuuduu search shows the total price. nuuduu bundle and nuuduu request ask for confirmation before charging, then let you pick a saved card from Atlas (default card first; press Enter to accept). Use --default-card to charge the default card without the picker (required for --json purchases).
Dataset directory
Resolved automatically via priority chain:
--dataset-dirCLI flagNUUDUU_DATASET_DIRenvironment variabledataset_dirin config fileHF_LEROBOT_HOME/nuuduu-atlas(LeRobot ecosystem default)- Project
.env, training configs, or./datasets/nuuduu-atlas - Fallback:
~/nuuduu-atlas/datasets
The dataset directory is created automatically on first sync if it does not exist.
nuuduu config show # shows resolved path and source
Local layout:
{dataset_dir}/
.nuuduu/manifest.json
lerobot/{download_uuid}/ # LeRobot v3.0 dataset
mcap/{download_uuid}/ # per-episode .mcap files
hevc/{download_uuid}/ # per-episode .mp4 files
CLI reference
nuuduu --help
nuuduu --version
nuuduu auth login
nuuduu auth logout
nuuduu auth token set TOKEN
nuuduu auth status
nuuduu config show
nuuduu config set KEY VALUE
nuuduu sync [--dataset-dir PATH] [--format lerobot|mcap|hevc|all] [--dry-run] [--verify]
nuuduu service-types [--json]
nuuduu search [--text QUERY] [--country fi,ee] [--service-types SLUG[,SLUG...]] [--limit N]
nuuduu bundle [--text QUERY] [--country fi,ee] [--service-types SLUG[,SLUG...]] [--limit N] \
[--min-episodes N] [--format lerobot|mcap|hevc] \
[--profile nuuduu] \
[--uuids UUID[,UUID...]] [--wait] [--yes] [--default-card]
nuuduu request --text "TASK" --episodes N [--country fi,ee] [--yes] [--default-card]
nuuduu request list
Add --json to any command for machine-readable output.
Shared search options
These options work the same on search and bundle (request supports --text and --country only):
| Option | Description |
|---|---|
--text / -t |
Semantic search query / task description |
--country / -c |
Comma-separated ISO 3166-1 alpha-2 codes (e.g. fi,ee,de); sent as country (not countries); lowercased before sending |
--service-types |
Comma-separated service type slugs; resolved to UUIDs via /api/atlas/assignments and sent as assignment on episode search |
--limit / -n |
Max episodes to search (defaults to 20; Atlas API caps at 100) |
Service types
List available service types (assignments) sorted alphabetically by slug:
nuuduu service-types
folding 7f3c2a91-...
pick-and-place a1b2c3d4-...
Filter search and bundle results by slug:
nuuduu search --text "fold a t-shirt" --service-types folding,pick-and-place
nuuduu bundle --text "fold a t-shirt" --service-types folding --min-episodes 100
nuuduu search prints a one-line summary with episode count and total price. nuuduu bundle shows a purchase preview and prompts for confirmation before charging your saved payment method.
Bundle-specific options
| Option | Description |
|---|---|
--format / -f |
Output format: lerobot (default), mcap, or hevc |
--profile |
LeRobot export profile (see Dataset profile) |
--min-episodes |
Target episode count; bundles what's available, then quotes a collection request for any shortfall (requires --text) |
--uuids / -u |
Comma-separated episode UUIDs (skips search when you already know them) |
--wait |
Poll until the bundle job is ready |
--yes / -y |
Skip bundle purchase and collection request confirmation prompts |
Dataset profile
Use --profile nuuduu on nuuduu bundle to export in the Nuuduu Ego LeRobot v3.0 layout. Field names, observation keys, and episode structure are defined in the Nuuduu Ego profile specification.
| Profile ID | Name |
|---|---|
nuuduu |
Nuuduu Ego |
Collection requests
Order new data to be collected when the library does not have enough:
nuuduu request --text "pick and place red blocks" --episodes 1000 --country fi,ee
Available now: 681 To collect: 319
Estimated total: $742.00
Confirm purchase? [Y/n]
After confirmation, Atlas collects the episodes. Run nuuduu sync as bundles become ready.
Note: the collection request API may return 404 until the backend endpoint is fully live — the CLI shows a preview of the intended UX when that happens.
Output formats
Bundles are written to your local dataset directory in one of these formats:
| Format | Contents | Best for |
|---|---|---|
lerobot (default) |
LeRobot v3.0 dataset (meta/, data/, videos/); use --profile nuuduu for the Nuuduu Ego profile layout |
PyTorch / LeRobot training |
mcap |
Per-episode MCAP files | ROS 2 / MCAP tooling |
hevc |
Per-episode HEVC MP4 files | Video analysis pipelines |
Integrity verification
When the Atlas API provides a sha256 field (SHA256 of the bundle zip), nuuduu sync:
- Verifies the downloaded zip before extracting
- Stores the hash in
.nuuduu/manifest.json - Skips re-download when the local hash matches
nuuduu sync --verify # re-check local bundles without downloading
Library API
| Class / function | Purpose |
|---|---|
NuuduuAtlas |
High-level facade (recommended) |
AtlasClient |
Low-level HTTP API client |
SyncEngine |
Sync and verify engine |
NuuduuConfig |
Config load/save |
resolve_dataset_dir() |
Dataset path resolution |
EpisodeSearchOptions |
Shared search parameters |
BundleResult |
Result of bundle_episodes() (download + optional collection request) |
Key methods on NuuduuAtlas:
| Method | Purpose |
|---|---|
search_episodes(text, country, limit) |
Search ready episodes |
bundle_episodes(text, country, min_episodes, ...) |
Bundle + optional collection request |
request_episodes(task, episodes, country) |
Quote/confirm a collection request |
sync(format, ...) |
Download ready bundles locally |
login() / logout() |
Manage API credentials |
Exceptions: AuthError, ApiError, IntegrityError, ConfigError, NotFoundError
Progress callbacks for sync:
from nuuduu.types import SyncProgressEvent
def on_progress(event: SyncProgressEvent) -> None:
print(event.phase, event.bytes_done, event.bytes_total)
atlas.sync(on_progress=on_progress)
Troubleshooting
| Problem | Solution |
|---|---|
| HTTP 401 | Run nuuduu auth login — token may have expired |
| Config permission error | Run chmod 600 ~/.config/nuuduu/config.toml |
| Payment failed / no payment method | Add or update your card at https://nuuduu.ai/atlas, then retry the bundle or request |
| SHA256 mismatch | Re-run nuuduu sync to re-download the bundle |
| Request API 404 | nuuduu request API not live yet — CLI shows the destination UX preview |
--min-episodes needs --text |
Provide a task description for the collection request |
Legal
Copyright © 2026 Nuuduu UAB. Licensed under the MIT License.
Nuuduu® is a registered trademark of Nuuduu UAB. All rights reserved. The Nuuduu name and logo may not be used to imply endorsement or affiliation without prior written permission from Nuuduu UAB.
Metadata
Release files for nuuduu 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nuuduu-0.7.0.tar.gz | 27.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nuuduu-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.2 kB
Release files / nuuduu-0.7.0.tar.gz
| Download URL | nuuduu-0.7.0.tar.gz |
|---|---|
| Size | 27.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74dc0963645d844700032e5b7cd1cb35bf49343e40bef383b76dba9c3ebe838b
|
|
BLAKE2b-256 checksum How to use checksums |
403f96f479add6d4c178433de9f00a65ef5cde93876ca07e62835cf6656782b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / nuuduu-0.7.0-py3-none-any.whl
| Download URL | nuuduu-0.7.0-py3-none-any.whl |
|---|---|
| Size | 37.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d231c048c3f24c12cf70d7a53f2bf2d8d08a56335d3e70cd159cfafa6160ab83
|
|
BLAKE2b-256 checksum How to use checksums |
dd3743285b5d79e47f07788523a78e0068dfb2a767e1887ff80d235be2c268b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|