YAAD GPU LAB

Student guide

Your team gets a private workspace on an NVIDIA DGX Spark: root access, the GPU, Docker, and internet access. You can also send batch jobs to the compute pool, which spreads them over all 8 Sparks in parallel.

GB10 GPU~119 GB unified memory 20 ARM cores3.5 TB disk ARM64 (aarch64)root + docker + internet
Using an AI agent? Paste this to it and it walks you through the whole setup, stopping where it needs you: Set me up for YAAD by following https://www.yaadops.com/agents#setup

★All YAAD tools at a glance

On the website (Lab page)

Sign inUWM email plus the emailed code. No password.
Your team workspaceCreate or join a team (with a team code), register up to 3 SSH keys (one per device), see your login line and usage, delete the team
Compute poolLive capacity of all Sparks. Submit a batch job (command, memory, CPUs, minutes, GPU, input folder, image), follow it, cancel it, get the download command.
Agent accessCreate or revoke personal tokens for your AI agent (Claude, OpenAI agents, any MCP client)
HelpSend a problem with screenshots, logs, or a screen recording. Replies from the CSI operator and host appear here.
Student guide · Agent guideThis page · how to connect and use AI agents

In your workspace (SSH terminal on the Spark)

nvidia-smiShows the GB10 GPU, memory use and the processes using it
apt · pip · sudoInstall anything. You are root; sudo is accepted so scripts run unchanged.
docker · docker composeRun NVIDIA / NGC containers in your team's own engine, GPU included (--gpus all works)
docker login nvcr.ioSign in to NGC with your own API key, for NVIDIA images that need it
yaad-diagOne report of GPU, memory, disk, your containers + logs, ports and versions. Attach it to a Help ticket.
/workspaceYour team's files. Kept until the event ends. Pool results land in /workspace/results/<job>.
$YAAD_PORT_BASEThe first of your team's 100 ports for web UIs (Jupyter, Gradio, Isaac Sim stream)
$ROS_DOMAIN_IDYour team's own ROS 2 domain, so other teams' topics don't mix with yours

On your computer

FortiClient (CSI VPN)Puts your device on the CSI network so it can reach the Sparks
ssh-keygenCreates the SSH key you register on the website (step 2)
ssh · VS Code Remote-SSH · Termius / BlinkLog in to your workspace
scp / sftpCopy files to /workspace and bring results back
ssh-add (ssh-agent)Unlocks a passphrase key once, so your AI agent can use ssh/scp without prompting (step 4)

Your AI agent's tools (MCP), see the agent guide

scope_jobWorks out how much memory, CPU and time to request, and whether the job fits one Spark
list_resourcesFree capacity on every Spark and the queue length
submit_job · get_job · list_jobs · cancel_jobRun batch jobs on any Spark with room, follow them, stop them
fetch_resultsThe command that copies a job's results to your computer
open_session · whoamiYour SSH login, your team, your home Spark
report_issue · my_issuesSend a problem to the CSI operator and host, and read the answers
wait_for_answerWaits for the reply to a ticket, so your agent can tell you the moment it's answered

1Before you start

A UWM email

Sign in on the Lab page with your @uwm.edu email. Only UWM addresses can sign in. We email you a sign-in code; type it in.

An SSH key on each device

This is how the Spark knows the device belongs to you. There are no passwords. It takes 1 minute per device: step 2.

The CSI VPN (FortiClient)

The Sparks are on the CSI network. Unless you are plugged into CSI's own network, connect the CSI VPN in FortiClient first. That includes campus Wi-Fi like eduroam and home.

The SSH key and the VPN do different jobs. The CSI VPN (FortiClient) puts your device on the CSI network. The SSH key proves to the Spark that the device is yours. You need a key on every device you log in from: laptop, desktop, iPad. You can register up to 3 keys, one per device.

2Get your SSH key

You make a key pair on your device. The private key never leaves the device. The public key (one line starting with ssh-ed25519) is what you paste on the website. Pick your device:

  1. Open PowerShell (Start menu → type PowerShell). It's a normal window; no admin needed.
  2. Create the key. Press Enter at every question to accept the default file. A passphrase is optional but recommended.
    PS> ssh-keygen -t ed25519
    Only press Enter at "Enter file in which to save the key". Don't type a command there, or the key is saved under that name.
  3. Copy the public key to the clipboard:
    PS> Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
    To see it instead: type $env:USERPROFILE\.ssh\id_ed25519.pub
  4. Paste it on the website (step 3). It is one line: ssh-ed25519 AAAA… csi\you@PC.
Using PuTTY instead of PowerShell?

PuTTY can't read this key directly. Open PuTTYgen → Conversions → Import key → choose C:\Users\<you>\.ssh\id_ed25519 (the file without .pub) → Save private key as id_ed25519.ppk. In PuTTY: Connection → SSH → Auth → Credentials → Private key file = the .ppk. Register the same public line from step 3.

Never share your private key. Paste only the line that starts with ssh-ed25519 (from the .pub file). Never paste a block that starts with -----BEGIN OPENSSH PRIVATE KEY-----, here or anywhere else.

3Register on the website

  1. Open the Lab page and sign in with your UWM email and the emailed code.
  2. One teammate creates the team: type a team name, paste their key, and click Create team. The page shows an 8-character team code.
  3. Everyone else joins: enter the team code, paste their own key, and click Join team. Each person uses their own key.
  4. More devices? In your team panel, paste one key per line (up to 3: laptop, desktop, iPad) under Replace my SSH keys.
  5. After about a minute the status shows Ready, with your login line, for example ssh yt-yourteam@172.30.102.9X.

4Connect

Connect the CSI VPN in FortiClient first, on every device (laptop, iPad), unless you are on the CSI network itself. Campus Wi-Fi (eduroam) is not enough.
PS> ssh yt-yourteam@172.30.102.9X        # exact line is on the website

Answer yes the first time (it remembers the Spark). For PuTTY, see the PuTTY note in step 2.

When your AI agent needs higher permission on your own computer (starting the ssh-agent service, installing FortiClient or other software, changing system settings), open the terminal it uses as administrator for those steps only. Windows: right-click PowerShell or Terminal → Run as administrator. Mac/Linux: run the step with sudo in Terminal (it asks for your computer password). Use admin mode only for the setup step, not for everyday work. Admin rights on the Spark are never needed: you are already root in your workspace.
Your key has a passphrase and an AI agent or script runs ssh/scp for you? They can't type the passphrase, so the login fails with Permission denied (publickey). Load the key into ssh-agent once:
# once, in PowerShell "Run as administrator"
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
# then in a normal PowerShell (asks for the passphrase once)
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Use Windows' own ssh/scp (C:\Windows\System32\OpenSSH). Git-for-Windows' ssh has a separate agent.

Copy files

$ scp data.zip yt-yourteam@172.30.102.9X:          # into /workspace
$ scp -r yt-yourteam@172.30.102.9X:results/<job_id> .   # bring results home

5Your workspace

You areroot in your team's own Ubuntu 24.04 + CUDA container. apt install and pip install work. sudo … works too, so install scripts run unchanged.
Your files/workspace. Kept between logins until the event ends. Other teams can't see them.
GPUnvidia-smi shows the GB10. Every container you start also gets it.
Dockerdocker and docker compose run in your team's own engine. --gpus all works, and so does -v /workspace/data:/data.
Internetapt, pip, Hugging Face, NGC, GitHub, build.nvidia.com
MemoryUp to 100 GB per team. CPU is shared fairly between the teams on a Spark.
Set for you$ROS_DOMAIN_ID (your own ROS 2 domain) and $YAAD_PORT_BASE (100 ports for your web UIs)
The Sparks are ARM64. Use linux/arm64 images and wheels. "exec format error" means an x86 image. To check an image before pulling it: docker manifest inspect <image> | grep arm64

5½Long runs, coding agents, and when the website is down

Your workspace does not need the website. Once your team shows Ready, ssh goes straight to your Spark. If the website, the compute pool or the help desk is down, keep working over SSH: run scripts, docker run --gpus all …, train, and copy files with scp. Save your ssh line somewhere. You only need the website to create or join a team, change keys, or use the pool.

Keep long runs alive when you disconnect. Closing your laptop or losing the VPN ends your SSH session and anything running in it.

$ apt install -y tmux
$ tmux new -s train            # start your run here; Ctrl-b then d to detach
$ tmux attach -t train         # come back later
$ nohup python train.py > /workspace/train.log 2>&1 &   # or this, then: tail -f /workspace/train.log

Save checkpoints to /workspace. A workspace restart stops running processes but keeps your files.

Install a coding agent in your workspace. It runs as root in your team's container and only sees your team's files. Sign in with your own account.

$ curl -fsSL https://claude.ai/install.sh | bash      # Claude Code; run: claude (it prints a sign-in link)
$ curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && apt install -y nodejs && npm i -g @openai/codex   # Codex CLI

If a browser sign-in can't reach the Spark, use an API key instead (ANTHROPIC_API_KEY or OPENAI_API_KEY). Your teammates can read files in /workspace and /root, so keep keys out of shared folders.

6Web UIs: Jupyter, Gradio, Isaac Sim stream, TensorBoard

$ echo $YAAD_PORT_BASE                                   # e.g. 20200; your range is +0..+99
$ jupyter lab --no-browser --ip 0.0.0.0 --port $YAAD_PORT_BASE

Open http://<spark-ip>:<port> (CSI network or CSI VPN), or tunnel: ssh -L 8888:localhost:<port> yt-yourteam@<spark-ip> → http://localhost:8888. Keep tokens and passwords on: other teams on the same Spark can reach open ports.

6½Isaac Sim quick start

arm64 imagesnvcr.io/nvidia/isaac-sim:6.0.0 and :5.1.0, nvcr.io/nvidia/isaac-lab:2.3.0. Isaac Sim 4.5 / 5.0 and Isaac Lab 2.2 are x86 only and fail with "exec format error".
LicenseThe image stops unless you set ACCEPT_EULA=Y and PRIVACY_CONSENT=Y.
First pullAbout 20 GB. It takes several minutes, once per Spark.

A. Batch / synthetic data (headless): a pool job

Put your script in a folder of /workspace (e.g. sdg/) and submit it from the Lab page or your agent:

{ "image": "nvcr.io/nvidia/isaac-sim:5.1.0",
  "env": { "ACCEPT_EULA": "Y", "PRIVACY_CONSENT": "Y" },
  "input_path": "sdg", "memory_gb": 48, "cpus": 8, "max_minutes": 120,
  "command": "/isaac-sim/python.sh /job/in/generate.py --out /job/out" }

The output lands in /workspace/results/<job>. Pool jobs run as root, so writing to /job/out works. Your command always runs as a bash script; the image's own startup (entrypoint) is skipped.

Tested recipes (2026-10-15, as pool jobs):

Isaac Lab RLnvcr.io/nvidia/isaac-lab:2.3.0, 56 GB / 12 CPUs, env ACCEPT_EULA=Y PRIVACY_CONSENT=Y OMNI_KIT_ACCEPT_EULA=YES:
cd /workspace/isaaclab && ./isaaclab.sh -p scripts/reinforcement_learning/rsl_rl/train.py --task Isaac-Cartpole-v0 --headless --num_envs 512 --max_iterations 30 && cp -r logs /job/out/
ROS 2 Jazzydocker.io/library/ros:jazzy, 8 GB / 4 CPUs. ROS is already sourced. apt-get install -y ros-jazzy-demo-nodes-cpp for the demos.
Cosmos Reason 7Bnvcr.io/nvidia/pytorch:25.01-py3, 40 GB / 8 CPUs, pip install transformers==4.51.3 qwen-vl-utils, bf16. The first load downloads ~16 GB (about 4 min); about 35 s per image description.

B. Interactive with the streaming client: your workspace

Run it in your workspace with docker. Use your ports: signalling on $YAAD_PORT_BASE, media on the next port.

$ docker run -d --name isaac --gpus all -u 0 --network host \
    -e ACCEPT_EULA=Y -e PRIVACY_CONSENT=Y -v /workspace:/workspace \
    nvcr.io/nvidia/isaac-sim:6.0.0 /isaac-sim/runheadless.sh \
    --/exts/omni.kit.livestream.app/primaryStream/signalPort=$YAAD_PORT_BASE \
    --/exts/omni.kit.livestream.app/primaryStream/streamPort=$((YAAD_PORT_BASE+1)) \
    --/exts/omni.kit.livestream.app/primaryStream/publicIp=<spark-ip>
$ docker logs -f isaac        # wait for "app ready" (first start: a few minutes of shader compiling)

On your computer (CSI VPN on), the Isaac Sim WebRTC Streaming Client always uses signalling port 49100. Tunnel it to your port and point the client at 127.0.0.1:

PS> ssh -N -o ServerAliveInterval=30 -L 49100:127.0.0.1:<YAAD_PORT_BASE> yt-yourteam@<spark-ip>
Stream won't reconnect after your Wi-Fi or VPN dropped (log: NVST_R_BUSY)? Isaac Sim keeps the dead session. Run docker restart isaac. The restart clears what is loaded, so save the stage to /workspace often (File → Save As → /workspace/scene.usd), and reopen it after the restart. ServerAliveInterval on the tunnel makes these drops rarer.
Share the GPU. A workspace session holds the GPU outside the pool's scheduler. Stop it when you're done (docker stop isaac) and use pool jobs (A) for long unattended runs.

Files: scp from your computer works (step 4). Inside the workspace you are root, so apt-get install -y python3 openssh-client adds missing tools.

7What you can run

Agent orchestration

NemoClaw in your workspace. It calls build.nvidia.com APIs (free key) or models served on the Spark.

workspace

Cosmos Reason (AOI, defects, RCA)

The arm64 container or HF weights. Cache models in /workspace (HF_HOME=/workspace/hf).

workspacepool

Inspection models: TAO, VisualChangeNet

NGC TAO/PyTorch arm64 images. Train as a pool job with image set.

pool

GenAI synthetic data (FLUX.2, Cosmos)

Inference fits the GB10. Fine-tuning: Edge with SFT, Nano with LoRA only. Bigger runs: Brev / build.nvidia.com.

workspacepool

Isaac Sim / Omniverse digital twins

Headless SDG as pool jobs, or stream it from your workspace: Isaac Sim quick start. Emulate3D runs on the Windows CSI workstation.

workspace

Robot policies: Isaac Lab

Long training runs as pool jobs with the Isaac Lab image. Write checkpoints to /job/out.

pool

ROS 2

docker run --rm -it --network host -e ROS_DOMAIN_ID ros:jazzy. For off-Spark links, use rosbridge/Zenoh on a port in your range.

workspace

NuRec, Kumo-TS, data prep

Python or NVIDIA containers in your workspace. Use pool jobs for training.

workspacepool

NGC images that need a login: docker login nvcr.io -u '$oauthtoken', then paste your NGC API key (from ngc.nvidia.com) as the password.

7½Downloading models (Hugging Face and more)

Your workspace and your pool jobs have internet access, so you can download open models from Hugging Face, NGC, GitHub, Ollama, Kaggle and similar sites. Model weights work on the ARM64 Sparks like anywhere else; only containers and Python wheels have to be ARM64.

Download once, into your workspace

$ export HF_HOME=/workspace/hf                       # Hugging Face cache that survives logins
$ pip install -U huggingface_hub
$ huggingface-cli download Qwen/Qwen2.5-7B-Instruct --local-dir /workspace/models/qwen7b
$ du -sh /workspace/models/qwen7b                     # how big it really is

Will it fit? Size in memory, not on disk

The Spark's GPU and CPU share one pool of memory (GB10, about 119 GB). What has to fit is the model while it runs:

Weightsbillions of parameters × bytes per parameter: bf16/fp16 = 2, fp8/int8 = 1, 4-bit (fp4/int4, GGUF Q4, AWQ) ≈ 0.5. An 8B model is ~16 GB in bf16, ~8 GB in fp8, ~4–5 GB in 4-bit.
Running it (inference)about weights × 1.2 + 6 GB (KV cache, activations, runtime). Long contexts (>32k tokens) need noticeably more.
LoRA fine-tuningabout weights × 1.25 + 0.4 GB per billion parameters + 10 GB. QLoRA (4-bit base) roughly halves it again.
Full fine-tuningabout 16 bytes per parameter (weights + gradients + Adam). Even an 8B model needs ~140 GB: use LoRA instead.

Your limits: a pool job up to 80 GB · your workspace up to 100 GB · a whole Spark ~119 GB · a 2-Spark job (nodes: 2) gives each half its own Spark, if your code splits the model (FSDP, DeepSpeed, tensor/pipeline parallel).

Running a modelbf16 · fp8 · 4-bit (approximate memory needed)
7–8B~26 GB · ~16 GB · ~11 GB, fits anywhere
13–14B~40 GB · ~23 GB · ~15 GB, fits anywhere
32B~83 GB (workspace only) · ~45 GB · ~26 GB
70Btoo big (~174 GB) · ~90 GB (workspace only, quiet Spark) · ~48 GB, pool job OK
100B+4-bit only, or 2 Sparks, or a hosted model on build.nvidia.com

Let scope_job do the math

Ask your AI agent, e.g. "Can I fine-tune Llama 3.1 8B with LoRA on YAAD?". It calls scope_job with the task, the model size and the precision. You get back:

scope_job { "task": "fine_tune_lora", "model_params_b": 8, "precision": "bf16" }
→ estimate ~34 GB, 8 CPUs · fits: pool_or_workspace · suggested_submit_job { memory_gb: 34, cpus: 8, ... } · availability_now: 6 Sparks

Estimates are rules of thumb. Ask for enough memory not to be killed for running out, but not so much that you block other teams. If a job dies with "out of memory", resubmit with a higher memory_gb.

8The compute pool

scope it→submit→queued→runs on any Spark with room→results in /workspace/results/<job>
commandA bash script. It runs as root in /job/in; write outputs to /job/out.
imageOptional, e.g. an NGC arm64 image. Blank means Ubuntu 24.04 + CUDA.
nodes1 (default) or 2: one rank on each of two cable-linked Sparks (see below).
envOptional environment variables, e.g. {"ACCEPT_EULA":"Y","PRIVACY_CONSENT":"Y"} for Isaac Sim. Up to 20 variables.
input_pathA folder in your /workspace, copied in as /job/in.
memory_gb · cpus · max_minutesReserved for you and enforced. Not sure what to ask for? Your agent's scope_job tool works it out.

Submit from the Lab page or let your AI agent do it (agent guide). If nothing has room, the job waits and starts by itself.

Two Sparks over the direct cable

Each pair of Sparks is joined by a 200G ConnectX-7 cable (RDMA, measured ~195 Gb/s). Set nodes: 2 (or tick 2 Sparks on the Lab page) to run one rank on each end: memory_gb and cpus are per Spark. Each rank gets RANK, WORLD_SIZE=2, MASTER_ADDR, MASTER_PORT and the NCCL network settings:

{ "nodes": 2, "image": "nvcr.io/nvidia/pytorch:25.10-py3", "memory_gb": 100, "cpus": 16, "input_path": "project",
  "command": "torchrun --nnodes 2 --nproc-per-node 1 --node-rank $RANK --master-addr $MASTER_ADDR --master-port $MASTER_PORT train.py" }

Rank 0's results land in /workspace/results/<job>/, rank 1's in results/<job>/rank1/. If one rank fails, YAAD stops the other. The job waits until both ends of a pair have room (list_resources → two_spark_pairs). Use a recent image (PyTorch 25.10 or later) so NCCL knows the GB10.

9Stuck? Get help

On the website

Lab page → Help: describe it, attach screenshots or logs, or click Record my screen. The answer appears there, usually within minutes.

From your AI agent

Ask it to "report this to YAAD". It calls report_issue, waits with wait_for_answer, and tells you the answer. A failed pool job opens a ticket by itself.

Attach diagnostics

In your workspace: yaad-diag > /workspace/diag.txt. It covers GPU, memory, disk, your containers and their logs, and ports.

Some fixes need the operator, for example more memory. Those show Waiting for operator approval, and you don't have to ask again.

10Not available, and what to do instead