Skip to content

armnet CLI

armnet-client installs several CLI entrypoints:

armnet --help                 # identity, secrets, volumes
armnet-policy-eval --help     # evaluate a policy backend on a cell
armnet-lerobot-eval --help    # evaluate a LeRobot policy on a cell
armnet-lerobot-train --help   # train locally with background remote evals
armnet-openpi-eval --help     # evaluate an OpenPI (pi0/pi0.5) policy on a cell
armnet-lerobot-teleop --help  # remote-teleoperate a cell from a leader arm
armnet-lerobot-record --help  # record a dataset via remote teleoperation
armnet-current-gate-derive --help # derive current safety limits from telemetry

The policy and teleoperation commands have dedicated guides: Teleoperate and Record Datasets, Train and Deploy a LeRobot Policy, and Evaluate Policies. The sections below are a quick reference for the most common invocations.

Identity

armnet whoami

Prints the username associated with your API key.

Jobs

armnet jobs list              # your most recent jobs
armnet jobs get <job-id>      # one job's status and result
armnet jobs logs <job-id>     # follow one of your jobs' live logs

jobs logs prints stdout in blue and stderr in red, the same way a job you submitted from this machine does. You can connect to a job that is already running, including from more than one machine. It only follows jobs submitted with your API key. A missing id, or a job submitted by someone else, is reported as job <id> not found. Lines from before you connect are not stored yet.

The connection counts as a log stream. A non-detached job stays up while one is connected, and closing the last one asks the cell to stop the job after a short grace period, same as closing the terminal that submitted it. A detached job is left running.

Useful for detached runs — manual-environment evals in particular, since those wait for an operator and can finish days after you submit them.

Secrets

armnet secret list
armnet secret create huggingface-token hf_...
armnet secret delete huggingface-token

Secret values are not printed by list.

Volumes

armnet volume upload ./checkpoint openpi/checkpoints/my-checkpoint
armnet volume cp openpi/checkpoints/my-checkpoint ./checkpoint
armnet volume ls                            # list the whole volume as a tree
armnet volume ls openpi/checkpoints         # list a sub-tree
armnet volume delete openpi/checkpoints/my-checkpoint

Uploads skip files that already exist in the cloud volume with the same hash, unless --overwrite is provided, and show a progress bar for large transfers. When a job references a volume:// path, the cell mirrors it down from the cloud (source of truth) before running and mirrors job outputs back up afterwards — see Volumes.

Current-gate profile derivation

Install the optional dependency and derive a cell current-safety profile from the robot-telemetry sidecars in one or more Hugging Face datasets:

pip install 'armnet-client[current-gate]'
armnet-current-gate-derive \
  --datasets datasets.json \
  --output current_gate_profile.json

datasets.json is a JSON list of Hugging Face dataset repo IDs. Use --cache-dir to reuse a specific Hub cache. The generated profile contains per-arm, per-joint percentiles and maxima suitable for the cell's robot.current_gate configuration; fleet operators should review it before deploying it.

LeRobot Evaluation

armnet-policy-eval \
  --policy.path=volume://policies/my-policy \
  --armnet.embodiment=lerobot/so-101 \
  --armnet.task=push_green_button \
  --eval.n_episodes=10

Each eval episode is recorded as a LeRobot dataset using the same streaming video encoding as data collection (software libsvtav1, which keeps episode saves fast and produces training-friendly video). Override with --armnet.vcodec, --armnet.encoder-threads, or disable streaming with --armnet.streaming-encoding=false. The same options apply to armnet-openpi-eval.

If your checkpoint is local, upload it while launching:

armnet-lerobot-eval \
  --policy.path=./outputs/train/my_policy/checkpoints/005000/pretrained_model \
  --armnet.volume_policy_path=policies/my-policy \
  --armnet.embodiment=lerobot/so-101 \
  --armnet.task=push_green_button \
  --armnet.rail=0.3

--armnet.rail homes and positions a calibrated rail before evaluation; its range is 0–1 from left to right. Only cells fitted with a rail accept it; omit it to use the cell's own default position. The value is checked before the job is queued against every cell that could take it, and rejected if it is outside what structured variation would itself produce there.

Add --armnet.variation=true to perturb rail position, camera aim, and lighting between episodes, and --armnet.variation-seed (default 42) to fix the sequence. Use --armnet.variation-rail, --armnet.variation-cameras, and --armnet.variation-lighting to isolate individual dimensions. See Evaluate Policies for the spread on each axis and what reproduces across runs.

OpenPI Evaluation

Evaluate an OpenPI (pi0 / pi0.5) checkpoint on a CUDA-capable cell. See Evaluate Policies:

armnet-policy-eval \
  --policy.type=openpi \
  --policy.path=volume://openpi/checkpoints/5000 \
  --policy.config_name=pi05_so101_stacking_rings \
  --armnet.n_episodes=3 \
  --armnet.task=ring_insert \
  --armnet.secrets="{HF_TOKEN: huggingface-token}"

GR00T Evaluation

Evaluate a NVIDIA GR00T N1.7 checkpoint by selecting the GR00T backend:

armnet-policy-eval \
  --policy.type=groot \
  --policy.path=https://huggingface.co/pravsels/groot1.7_insert_candle \
  --armnet.embodiment=lerobot/so-101 \
  --armnet.task=insert_candle \
  --armnet.n_episodes=1

--policy.type=groot is N1.7. CRA GR00T N2 is --policy.type=cra and is SO-101 BusyBox only.

CRA GR00T N2 Evaluation

armnet-policy-eval \
  --policy.type=cra \
  --policy.path=pravsels/cra_busybox_multitask_h48_cosine_20k \
  --policy.num_inference_timesteps=4 \
  --policy.actions_to_execute=16 \
  --armnet.embodiment=lerobot/so-101 \
  --armnet.task=busybox_left_toggle_down \
  --armnet.n_episodes=1 \
  --armnet.language_instruction='Turn the left toggle switch down to "Off" position' \
  --armnet.secrets="{HF_TOKEN: huggingface-token}"

Each image build fetches CRA origin/main from external/cra (GitHub access to NVIDIA/Isaac-GR00T-CRA is required). --policy.path may be a Hub repo id (cached under the cell HF_HOME) or volume://cra/checkpoints/... (never Hub-downloaded).

--policy.action_ticket_seed samples one action-noise tensor for the job. --policy.action_ticket_path loads a volume:// .npz instead. They are mutually exclusive, and either one rejects --policy.use_torch_compile. With neither flag, action noise stays on the fixed policy seed 42. The result reports an action_ticket fingerprint and does not include the raw tensor. See Evaluate Policies for sampling, volume upload, and the hardware commands. Do not run those commands until a human authorizes real hardware.

LeRobot Training with Remote Evals

armnet-lerobot-train \
  --output_dir=outputs/train/my_policy \
  --save_freq=2000 \
  --armnet.eval.n_episodes=10 \
  --armnet.eval.embodiment=lerobot/so-101 \
  --armnet.eval.task=push_green_button

Remote Teleoperation

Drive a remote cell's follower from locally-attached leader arm(s), streaming the follower back into Rerun — no data recorded (requires pip install 'armnet-client[teleop]'). See Teleoperate and Record Datasets:

armnet-lerobot-teleop \
  --teleop.port=/dev/ttyACM0 \
  --teleop.id=my_leader \
  --armnet.duration_s=300

For a bimanual YAM cell, pass both local leader ports instead of --teleop.port and set --armnet.embodiment=lerobot/bimanual_yam.

Use --rail 0.3 with teleoperation or recording to home and position the cell's calibrated rail at 30% before the session starts. The accepted range is 0–1. Omit it to use the cell JSON rail.default_position_percent default (0–100 percent); cells without rail calibration do not move.

Each configured rail homes once before the job container starts, moves to the job's requested position, and keeps torque enabled to hold that position. Later position requests within the job move directly only when the persisted settled position still matches both the rail calibration and stable live encoder continuity. Missing or interrupted state, changed calibration, or an encoder mismatch/unstable reading makes the rail safely re-home before continuing; the recovery is reported once in the job output. A request already at its target restores holding torque without traversing the rail. Environment reset plans may temporarily stage a rail at another pose, but the runtime restores the job position directly before the reset returns and the next episode begins.

Use --lightbox-brightness 30 and --lightbox-frequency 4000 to override the cell's lightbox brightness (percent 0–100) and PWM frequency (Hz) for the session. Omit either flag to keep that cell default. Cells without a lightbox ignore both.

For an SO-101 session, --goal-velocity-limit 1001 and --acceleration-limit 40 request per-job servo caps. Both values are raw STS3215 register units: goal velocity accepts 1–3250 and acceleration accepts 1–254. The edge still enforces the cell-configured caps, so a job cannot loosen them. These flags are rejected for bimanual YAM. A torque re-enable restores the cell caps, so use these per-job flags for uninterrupted sweep runs rather than as persistent safety settings.

During armnet-lerobot-teleop, press Right Arrow to print a ready-to-paste joint keypoint (for authoring BusyBox reset motion plans). Pass --capture-interval-s=1 to also auto-print a keypoint every second while the leader is commanding.

LeRobot Dataset Recording (Remote Teleop)

Record a LeRobot dataset on a remote cell by driving its follower from a locally-attached leader arm, or a left/right leader pair for bimanual cells (requires pip install 'armnet-client[teleop]'):

armnet-lerobot-record \
  --teleop.port=/dev/ttyACM0 \
  --teleop.id=my_leader \
  --dataset.repo_id=my_user/so101_pick_place \
  --dataset.single_task="Grab the black cube" \
  --dataset.num_episodes=10 \
  --secret HF_TOKEN=huggingface-token

For bimanual recording, use --teleop.left-port and --teleop.right-port, and name the task with --armnet.task; the orchestrator routes it to a cell set up for that task's environment.

The dataset is recorded inside the cell — your machine only streams leader joint positions — and pushed to the Hugging Face Hub when the session ends (--no-push-to-hub to skip). Camera frames are encoded to video in real time so saving an episode is near-instant.

LeRobot's standard recording shortcuts work during the session:

  • Right Arrow: save the episode; the remote arm returns to rest and the next episode starts once the workspace is reset.
  • Left Arrow: discard the episode and re-record it (same reset flow).
  • Esc: stop the session, finalize and upload the dataset.

See Teleoperate and Record Datasets for the dataset options and the arm-current safety gate.