$npx -y skills add wshobson/agents --skill spark-environment-setupSet up a working ML training/inference environment on NVIDIA DGX Spark (GB10, aarch64, CUDA 13). Use when installing PyTorch/Unsloth/TRL/vLLM on DGX Spark, hitting libcudart or wheel-ABI errors on aarch64, or choosing between NGC containers and bare pip installs.
| 1 | # Spark Environment Setup |
| 2 | |
| 3 | DGX Spark ships a GB10 Grace Blackwell chip: aarch64 CPU, SM121 |
| 4 | GPU, 128GB unified memory, CUDA 13. This is a narrower and |
| 5 | younger platform than a standard x86 CUDA 12 box, so package |
| 6 | selection and ABI matching matter more than usual — the wheel |
| 7 | ecosystem for aarch64 + CUDA 13 is still filling in. |
| 8 | |
| 9 | ## When to Use This Skill |
| 10 | |
| 11 | - Setting up a fresh Spark box for training or inference. |
| 12 | - Hitting an import error mentioning `libcudart`, a missing |
| 13 | symbol, or a wheel that "installed fine but won't load." |
| 14 | - A framework install (PyTorch, Unsloth, TRL, vLLM, xformers) |
| 15 | fails, hangs, or silently falls back to CPU. |
| 16 | - Deciding whether to use an NGC container or bare pip. |
| 17 | - Restoring a working setup after an OS reinstall or a |
| 18 | base-image update, needing to re-verify from scratch. |
| 19 | |
| 20 | Each of these accepts the same general fix: match the |
| 21 | container/wheel combination to CUDA 13 and SM121, don't fight |
| 22 | the ABI. |
| 23 | |
| 24 | ## Container-First Rule |
| 25 | |
| 26 | Quick decision, before the detail below: |
| 27 | |
| 28 | - Standard training/inference work → NGC PyTorch container. |
| 29 | - Unsloth-centric fine-tuning → Unsloth container (it ships |
| 30 | the pinned Triton/xformers/transformers combination already |
| 31 | validated for that path). |
| 32 | - Neither fits (custom system package, local IDE interpreter) |
| 33 | → bare pip, following the exact sequence further down. |
| 34 | |
| 35 | Default to a container. Use `nvcr.io/nvidia/pytorch:25.09-py3` |
| 36 | as the base for general work — the newest tag confirmed working |
| 37 | on this hardware; pull a newer blessed tag if locally available |
| 38 | rather than hard-blocking on `25.11-py3`. NGC's tag is dated, so |
| 39 | running it directly is fine: |
| 40 | |
| 41 | ```bash |
| 42 | docker run --runtime=nvidia --gpus all -it --rm \ |
| 43 | nvcr.io/nvidia/pytorch:25.09-py3 |
| 44 | ``` |
| 45 | |
| 46 | `unsloth/unsloth:dgxspark-latest` is a *moving* tag by |
| 47 | contrast — resolve and pin its digest before running it for |
| 48 | anything reproducible; the bare tag is a discovery step only, |
| 49 | not the default invocation. Full pull-inspect-pin sequence and |
| 50 | flag rationale/volume mounts for `finetuning/` run dirs: |
| 51 | `references/container-workflow.md`. Treat bare pip as the exception. |
| 52 | |
| 53 | The reason for the container-first stance is pinning, not |
| 54 | convenience. Triton, xformers, and transformers versions |
| 55 | interact narrowly with GB10's SM121 target and CUDA 13; a |
| 56 | container locks all of them together against a combination |
| 57 | already validated on this hardware. Bare pip leaves that |
| 58 | resolution to you, one broken import at a time. |
| 59 | |
| 60 | When bare pip is warranted, follow the NVIDIA playbook's |
| 61 | install sequence verbatim and in order: |
| 62 | |
| 63 | ```bash |
| 64 | pip install "transformers==5.13.1" "peft==0.19.1" "hf_transfer==0.1.9" "datasets==4.3.0" "trl==1.8.0" |
| 65 | pip install --no-deps "unsloth==2026.7.2" "unsloth_zoo==2026.7.2" "bitsandbytes==0.49.2" |
| 66 | pip install -U "torchao==0.17.0" |
| 67 | ``` |
| 68 | |
| 69 | The second command's `--no-deps` flag is not optional — |
| 70 | letting pip re-resolve Unsloth's dependency tree on aarch64 is |
| 71 | a common way to pull in an incompatible torch or triton build. |
| 72 | The third line is not optional either: the NGC base image's |
| 73 | bundled `torchao` is too old for current `peft`'s LoRA-attach |
| 74 | path (`ImportError: ... torchao ... only versions above 0.16.0 |
| 75 | are supported`) — a hard blocker, not a warning. Every `==` pin |
| 76 | above is load-bearing, taken from the dated known-good version |
| 77 | matrix in `references/stack-matrix.md` (its `Last verified` date |
| 78 | governs staleness) — an unpinned install resolves current PyPI |
| 79 | versions well outside what this Unsloth release supports. |
| 80 | |
| 81 | Pull a fresh tag when a new blessed release is announced. |
| 82 | Rebuild locally from one of the two bases only when a project |
| 83 | needs an extra system package layered in — not to "upgrade" a |
| 84 | component the image already pins. Details on both paths: |
| 85 | `references/container-workflow.md`. |
| 86 | |
| 87 | One more preflight: official DGX Spark playbooks have shipped |
| 88 | broken before. Check recent issues on |
| 89 | `github.com/NVIDIA/dgx-spark-playbooks` (and the other |
| 90 | resources in `references/stack-matrix.md`) before trusting a |
| 91 | recipe verbatim for a long run. |
| 92 | |
| 93 | ## The ABI Rule |
| 94 | |
| 95 | The single most common failure on Spark is a CUDA 12/13 ABI |
| 96 | mismatch: a wheel built against `libcudart.so.12` loaded on a |
| 97 | system that only has `libcudart.so.13`. The install usually |
| 98 | succeeds; the failure surfaces later as a missing-symbol error |
| 99 | or a segfault that doesn't obviously point at CUDA. |
| 100 | |
| 101 | Fix: pull wheels from `download.pytorch.org/whl/cu130` (the |
| 102 | cu130-tagged aarch64 builds), or use one of the containers |
| 103 | above, which already carry a matched build. Before chasing a |
| 104 | stack trace that mentions a CUDA symbol, check which CUDA tag |
| 105 | the installed wheel was built against: |
| 106 | |
| 107 | ```bash |
| 108 | python3 -c "import torch; print(torch.version.cuda)" |
| 109 | ``` |
| 110 | |
| 111 | If that output doesn't start with `13`, the ABI mismatch is |