Skip to content
LotusMake

Back to The Aeon Forge

Post

ComfyUI for the DGX Spark: the AEON media production base

A Docker build of ComfyUI for the DGX Spark with CUDA 13, SageAttention v3 for sm_121a and NVFP4 weights, pulling Flux 2, LTX 2.3 and ACE-Step on first start. What broke, what the flags mean, how local and remote modes work, and why three AEON media repos sit on it.

10 min read

by The Aeon Forge

The DGX Spark is an odd machine to build media tooling for. It pairs a Blackwell GPU with an ARM64 CPU and 128 GB of LPDDR5X memory that the two share, and nearly every ComfyUI container I tried failed on it in one of three ways: the wrong CPU architecture, a CUDA build that had never heard of its compute capability (the GPU's instruction-set version), or attention kernels that produced garbage. I wanted image, video and audio generation working on a fresh Spark in about an hour, as a server my other projects could call rather than a notebook I tended by hand.

comfyui-aeon-spark is the result: a Docker distribution of ComfyUI for the GB10 with CUDA 13.0.2, PyTorch 2.9.1 for CUDA 13, SageAttention v3 (a low-precision attention kernel) compiled from source for sm_121a, and NVFP4 weights, a four-bit floating-point format with per-block scales that Blackwell tensor cores run natively. Three of the AEON media repos stand on it. Here is how it came together, scars included.

github.com/AEON-7/comfyui-aeon-spark↗

AEON-7/comfyui-aeon-spark

Bleeding-edge ComfyUI for NVIDIA DGX Spark (GB10/Blackwell/sm_121a). CUDA 13 + SageAttention v3 (sm_121a) + NVFP4 + 14 custom-node packs + Flux 2 Dev / LTX 2.3 22B / ACE-Step v1.5 XL Turbo pre-bundled with abliterated text-encoder paths.

Shell · updated 2026-10-06

Load the latest from GitHub

What ships in the image

The image is 17 GB in either tag and contains no model weights. latest adds a first-start downloader that pulls Flux 2 Dev, LTX 2.3 22B and ACE-Step v1.5 XL Turbo, about 285 GB in all, with NVFP4 alternates and abliterated text-encoder paths (encoders with the refusal direction removed from their weights); plan on 350 GB of free disk. slim is the code alone, starts in about 50 GB, and takes its models from the in-UI Manager. Every weight comes from Hugging Face under your own token and licence acceptance: the FLUX.2, Mistral-Small-3 and Gemma licences forbid redistribution, and I will not ship an image that violates them.

At build time the runtime was Python 3.12.3, Triton 3.5.1, Diffusers 0.37.1, Transformers 5.7.0 and ComfyUI 0.20.1. The compose file runs two services: comfyui on port 8188 as the container comfyui-spark, and an internal ollama that pulls gemma3:4b, about 3 GB, to expand short prompts for the music workflow. One host volume, workspace/, holds models, custom nodes, output, input and saved workflows; delete the container, remount it, and everything returns.

Why CUDA 13 was not optional

The GB10 reports compute capability 12.1 with an architecture-specific suffix, sm_121a. No CUDA 12.x toolchain can emit code for it; CUDA 13.0.2 is the first that can. That one fact ruled out every prebuilt ComfyUI image I tried.

SageAttention v3 is compiled from source with -gencode=arch=compute_121a,code=sm_121a plus a compute_121,code=sm_121 target. PyTorch itself ships sm_120 machine code and compute_120 PTX, an intermediate form the driver compiles forward to sm_121a on each kernel's first run and then caches. That is why the first launch can sit at "Starting server" for more than ten minutes. It is not frozen.

Familiar pieces are absent on purpose. FlashAttention 2, 3 and 4 have no sm_121 kernels, so SageAttention is the only fast path. xformers has no wheel for this architecture. torch.compile is off through TORCH_COMPILE_DISABLE=1 because Triton does not yet emit working machine code for sm_121a. bitsandbytes gives way to GGUF and NVFP4, and TensorRT engines are left out because they are tied to one compute capability. The runbook makes these rules: never strip --use-sage-attention; never pip-install sageattention or a node pack by hand, since a stock wheel replaces the working sm_121a build; never enable torch.compile, xformers or FlashAttention, which corrupt output or crash.

Unified memory changes the usual advice

On a discrete GPU, pinned host memory and keeping everything on the device are the standard speedups. On Grace-Blackwell, where CPU and GPU share one coherent pool, both hurt. So ComfyUI starts with --disable-pinned-memory, --gpu-only stays off, utilisation is capped at 0.88, and --reserve-vram 2.0 leaves the operating system scratch space under that cap. The VAE, the small network that turns latents into pixels, and the text encoders run in BF16 because, with 128 GB, the precision is nearly free. The container gets a 32 GB shared memory segment.

The flag I got wrong is the UNet dtype. The Flux 2 Dev checkpoint is a mixed FP8 file, and the UNet flag must match the file it loads. One commit fixed the flag; the README, the validation script and the runbook were not all reconciled afterwards, and as I write they still disagree. The rule holds regardless: the UNet flag follows the checkpoint.

NVFP4 without a switch

There is no NVFP4 flag in this build. Load a file whose name ends in _fp4_mixed.safetensors in a CLIPLoader or UNETLoader node and its matrix multiplies go to the CUDA 13 CUTLASS FP4 GEMMs, the matrix-multiply kernels for that format; load the BF16 file and they do not. Swapping one loader widget from mistral_3_small_flux2_bf16 to mistral_3_small_flux2_fp4_mixed trades a little quality for throughput and a great deal of memory.

The Mistral-3 Small encoder behind Flux 2 is 35.6 GB in BF16 and 12.3 GB in NVFP4-mixed; the Gemma-3 12B IT encoder behind LTX 2.3 is 24.4 GB against 9.4 GB. An encoder swap saves about 24 GB and is the first thing to try when a workflow runs out of memory. Hopper, Ada and Ampere run the image without the FP4 hardware path. Consumer Blackwell such as the RTX 5090, which is sm_120 on x86, needs a rebuild:

Code, shelldocker buildx build --platform linux/amd64 -t comfyui-aeon-spark:x86 .

The models the downloader pulls

Flux 2 Dev is the image model, a 32-billion-parameter diffusion transformer whose mixed-FP8 file is 35.5 GB, under a non-commercial licence to review before paid work. Flux 2 Klein 9B is the smaller gated alternative behind workflow 08. LTX 2.3 22B is the video model: 42 GB in BF16, 23.5 GB as an FP8 scaled file, 29 GB as a fused FP8 checkpoint, and choosing FP8 over BF16 saves about 18 GB. ACE-Step v1.5 XL Turbo is the music model, a 9.97 GB BF16 transformer.

Then come the abliterated text encoders, about 70 GB of full snapshots: 48 GB of Mistral-Small-3.2 24B and 24 GB of Gemma-3 12B, which encode a prompt as written rather than softened. They inherit the parent licences, and SKIP_ABLITERATED=1 in .env skips them.

Before the first start, accept three gated repositories on Hugging Face: FLUX.2-dev, FLUX.2-klein-base-9b-fp8 and FLUX.2-small-decoder. With a Read-scope token in place, the download runs about 45 to 50 minutes at roughly 95 MB/s over 10 GbE, after an image pull of about 5 minutes, and ends with 35 ok, 0 failed. Without the Klein licence it is 34 and one failure.

Node packs and the nine workflows

The README lists sixteen bundled node packs; the repository's one-line description still says fourteen, a count I have not reconciled. The ones that matter most are ComfyUI-Manager, ComfyUI-LTXVideo with its 94 nodes, ComfyUI-GGUF, KJNodes, VideoHelperSuite, RES4LYF, whose ClownSampler_Beta the distilled LTX workflow needs, ComfyUI-Ollama, kijai's ComfyUI-PromptRelay for per-second prompt timelines in video, and my own aeon-server-side-downloads. With ComfyUI core they register about 1728 backend nodes.

Nine workflow files are seeded into user/default/workflows/, numbered 01 to 05 and 07 to 10; the gap at 06 is real, and some of my own text still says eight. The distilled LTX workflow runs 8 steps with a 7.6 GB LoRA, a small adapter trained on top of the base model.

File What it does
01 Flux 2 Dev text to image
02 LTX 2.3 distilled text or image to video
03 Two-stage text to video
04 Image to video
05 First and last frame to video
07 ID-LoRA
08 Flux 2 Klein 9B
09 ACE-Step XL Turbo with Ollama prompt expansion
10 LTX 2.3 with the prompt relay timeline
The seeded workflows.

Why three media repos stand on it

The media repos are thin clients. aeon-music-maker, aeon-radio-drama and aeon-movie-maker each assemble a workflow JSON and post it to ComfyUI over HTTP at COMFYUI_URL, which defaults to http://127.0.0.1:8188, with COMFYUI_ROOT telling them where output lands. They do not load models or know what sm_121a is. aeon-movie-maker also uses the PromptRelayEncodeTimeline node from the bundled PromptRelay pack, so a script's per-second prompt changes become one encoded timeline. aeon-music-video is the exception: it is CPU-only, needs neither ComfyUI nor a GPU, and lists this repo only as a sibling. The family has four members and three of them depend on this base. The point of the split is that a fix lands once: when a driver update breaks a kernel, I repair this image and the three clients keep working untouched, and a new client needs only an HTTP endpoint and a workflow file. The speech siblings, the Qwen3 TTS server and the Qwen3 ASR server, sit beside it in the catalog.

Local and remote modes

The client READMEs describe two arrangements. In mode A the client runs on the Spark and COMFYUI_URL stays at its loopback default. In mode B, ComfyUI runs on the GPU box and the client runs elsewhere. B1 is direct HTTP: start ComfyUI with --listen 0.0.0.0, since it binds to loopback by default, open port 8188 on that machine, point the client at http://<gpu-box-ip>:8188, and leave COMFYUI_ROOT unset so output is written on the client side. B2 is an SSH tunnel that forwards a local port to the Spark's 8188 and needs no firewall change.

Remote use is why the server-side download pack exists. The Missing Models dialog in ComfyUI 0.20 has a Download button that downloads into the browser, which in mode B is the wrong machine. aeon-server-side-downloads intercepts the click and routes it through the Manager's queue API so the file lands on the server, falling back to the browser download if Manager is unreachable.

Getting it running

The Spark has one GPU, so stop any other heavy GPU service first; in my lab that is the vLLM container. You need DGX OS (Ubuntu 24.04) with the 580 driver, Docker 28 or newer with the NVIDIA container runtime, a free Hugging Face account with a Read-scope token, and the disk space above. Then:

Code, shellgit clone https://github.com/AEON-7/comfyui-aeon-spark.git
cd comfyui-aeon-spark
./setup.sh
docker logs -f comfyui-spark

Open port 8188 in a browser once the log prints Launching ComfyUI on port 8188. To update, never re-clone and never re-run setup.sh; use the sync script, which accepts --yes and --no-models:

Code, shellcd comfyui-aeon-spark
./sync.sh

A 403 is a gated repository you have not accepted; a 401 is a bad token or one without Read scope. A container restarting every 30 seconds is being killed by its health check before the slow first start finishes; raise start_period to 1200 seconds. Out-of-memory errors answer to "Free memory" in the UI, then to NVFP4 encoders, then to the FP8 LTX DiT. Workflow 09 fails without the Ollama sidecar. If a download dies halfway, remove workspace/.models_seeded, recreate the container, and the downloader runs again.

Sources

  • The AEON Forge catalog: every project and what to read first

    A guided tour of the AEON Forge catalog: NVFP4 models for the DGX Spark, MLX builds for Apple Silicon, the voice stack, the media tools, the Orb and the Bench, with the article to read first in each group.

    The Aeon Forge11 min read
  • Qwen 3.8 27B AEON Ultimate: the current flagship and how to serve it

    Qwen3.8-27B AEON Ultimate Uncensored is the model I now serve on one Spark, two Sparks and the RTX box: what coherent abliteration removes and keeps, the NVFP4-MIXED weight lattice, the three seat recipes with their commands, and the rules that keep them running.

    The Aeon Forge14 min read
  • Serving Qwen 3.6 35B-A3B heretic at NVFP4 with DFlash on a DGX Spark

    How I serve an uncensored Qwen 3.6 35B-A3B at NVFP4 with DFlash speculative decoding on one DGX Spark: the seven container fixes, the mixture-of-experts angle, the drafter, the measured numbers and the exact command that works today.

    The Aeon Forge11 min read
  • Ornith 1.0 35B AEON Ultimate keeps the coding and drops the refusals

    I abliterated DeepReinforce's Ornith 1.0 35B, an agentic coding MoE, and kept the coder: 0 of 80 refusals, pass@1 identical to the base, a three-way BF16, NVFP4 and DFlash benchmark on a DGX Spark, and the quick start to serve it.

    The Aeon Forge10 min read
  • Nemotron 3 Nano Omni AEON Ultimate, served uncensored on a DGX Spark

    An abliterated Nemotron 3 Nano Omni that reasons over text, images and audio on one DGX Spark. How the twelve-dimension refusal removal was found, what NVFP4 costs against BF16, what the source-built vLLM image patches, and how to deploy it.

    The Aeon Forge9 min read

Stoke the forge. From $4, straight to The Aeon Forge.