Overview
This page collects battle-tested patterns that have emerged from building and shipping apps on Thumper-Run. Each pattern solves a specific problem we’ve encountered repeatedly. Below the patterns you’ll also find anti-patterns — common mistakes that look reasonable but lead to broken installs, OOM crashes, or silent failures.
Use these as a reference when writing your .thumper.yaml manifests. Every pattern includes a YAML snippet you can copy directly into your manifest.
Patterns
The following six patterns cover the most common scenarios you’ll encounter when packaging apps for Thumper-Run. Each one has been extracted from production manifests and tested across NVIDIA, AMD, and CPU-only hardware.
1. GPU Fallback Chain
Test for CUDA first, then ROCm, then MPS (Apple Silicon), and finally fall back to CPU. Use conditional patches so the right flags are applied automatically based on the detected GPU vendor.
# .thumper.yaml — GPU fallback chaingpu:required: falsepreferred_backends: [cuda, rocm, mps, cpu]patches:- name: cuda-flagscondition: { gpu_vendor: nvidia }env:CUDA_VISIBLE_DEVICES: "0"TORCH_DTYPE: "float16"- name: rocm-flagscondition: { gpu_vendor: amd }env:HSA_OVERRIDE_GFX_VERSION: "11.0.0"TORCH_DTYPE: "bfloat16"- name: cpu-fallbackcondition: { gpu_vendor: none }env:FORCE_CPU: "1"
2. Ollama Auto-Start
Declare Ollama as a dependency and let the launcher handle starting it, pulling models, and overriding the port. This eliminates manual Ollama setup for end users.
# .thumper.yaml — Ollama auto-startdependencies:- name: ollamaauto_start: trueollama_port_override: 11435models:- ollama_tag: "llama3.2:3b"models_required: true- ollama_tag: "nomic-embed-text"models_required: false
When the app launches, Thumper-Run calls auto_pull_ollama_models() for each model tagged with an ollama_tag. Required models block launch until downloaded; optional models pull in the background.
3. Model Pack Composition
Use pack_refs to compose model packs from individual model manifests. Mark critical models as required and optional enhancers as non-required so the app can still launch without them.
# pack.yaml — SDXL Starter Packname: sdxl-starterversion: "1.0.0"models:- ref: sdxl-base-v1.0models_required: trueslot: checkpoint- ref: sdxl-vae-fp16models_required: trueslot: vae- ref: sdxl-refiner-v1.0models_required: falseslot: refiner
When models_required is true, the install pipeline treats a download failure as fatal and rolls back. When false, the app installs successfully and the missing model can be downloaded later from the model hub.
4. Health Check with Backoff
Configure a health check endpoint with enough retries and interval to handle slow model loading. Without this, the app appears stuck at "Starting" and users assume it’s broken.
# .thumper.yaml — health check with backoffhealth_check:url: "http://127.0.0.1:8188/system_stats"retries: 30interval: "2s"timeout: "5s"expected_status: 200
With 30 retries at 2-second intervals, the launcher waits up to 60 seconds for the app to become healthy. This is enough for most GPU model loading scenarios. For very large models (30+ GB), increase retries to 60.
5. Patch Layering
Layer patches from general to specific: base patches apply to all platforms, GPU-vendor patches override for specific hardware, and OS-specific patches handle filesystem differences.
# .thumper.yaml — patch layeringpatches:# Base — applies everywhere- name: base-configenv:LOG_LEVEL: "info"MAX_WORKERS: "4"# GPU vendor — overrides base- name: amd-perfcondition: { gpu_vendor: amd }env:MIOPEN_FIND_MODE: "2"PYTORCH_HIP_ALLOC_CONF: "expandable_segments:True"# OS-specific — filesystem paths- name: linux-pathscondition: { os: linux }env:CACHE_DIR: "$HOME/.cache/app-name"
Patches are applied in order. Later patches can override values set by earlier ones. Conditions can combine gpu_vendor and os for precise targeting.
6. Resumable Downloads
Large model files (often 2–10 GB each) can fail mid-download due to network issues. The install pipeline uses .part temporary files and HTTP Range headers to resume interrupted downloads automatically.
# model.yaml — resumable download configfiles:- name: "sdxl-base-v1.0.safetensors"download_url: "https://hf.co/stabilityai/sdxl/resolve/main/sd_xl_base_1.0.safetensors"sha256: "31e35c80fc4829d14f90153f4c74cd59c90b779f6afe05a74cd6120b893f7e5b"size_bytes: 6938040682
During download, a .part file is written to disk. If the download is interrupted, the next attempt sends a Range header starting at the .part file size. After completion, the .part suffix is removed and the SHA-256 checksum is verified against the manifest.
Anti-Patterns
These are mistakes we’ve seen repeatedly in manifest files and launch configurations. Each one includes the wrong approach and the correct fix.
1. Hardcoded GPU Paths
Hardcoding CUDA library paths breaks the app on AMD and CPU-only systems.
Wrong:
env:LD_LIBRARY_PATH: "/usr/lib/cuda/lib64"
Right:
patches:- name: cuda-libscondition: { gpu_vendor: nvidia }env:LD_LIBRARY_PATH: "/usr/lib/cuda/lib64"
2. Missing Health Check
Without a health check, the launcher marks the app as Running before it’s actually ready. Users see a blank or error page.
Wrong:
# No health_check section at alllaunch:command: "python main.py"
Right:
launch:command: "python main.py"health_check:url: "http://127.0.0.1:8080/health"retries: 30interval: "2s"
3. FP16 on AMD APU
FP16 precision causes NaN outputs on AMD APUs because the DiT attention layers overflow (FP16 max is ~65504). Always use BF16 on AMD hardware.
Wrong:
env:TORCH_DTYPE: "float16" # NaN on AMD APU!
Right:
patches:- name: amd-precisioncondition: { gpu_vendor: amd }env:TORCH_DTYPE: "bfloat16"
4. Fire-and-Forget Launch (process_group)
Using process_group(0) to launch GUI apps (Electron, AppImage) causes SIGTSTP when the child calls tcsetpgrp() for terminal access. The process silently stops with status T. Use setsid() instead, which creates a new session with no controlling terminal.
Wrong:
launch:process_group: true # SIGTSTP kills Electron apps
Right:
launch:new_session: true # setsid() — no controlling terminal
5. Smart Memory + GPU Text Encoder on APU
On AMD APUs with shared memory, running the text encoder on GPU leaves ~7 GB residual VRAM that smart memory only partially evicts. When the VAE runs, it OOMs. Move the text encoder to CPU and let smart memory manage the diffusion model.
Wrong:
# All models on GPU — OOM during VAE stageenv:DEVICE: "cuda"
Right:
patches:- name: apu-memorycondition: { gpu_vendor: amd, gpu_type: apu }env:TEXT_ENCODER_DEVICE: "cpu"DIFFUSION_DEVICE: "cuda"
6. --lowvram on APU
The --lowvram flag enables per-layer GPU offloading, which sounds helpful for memory-constrained systems. On APUs, however, the GPU and CPU share the same physical RAM, so offloading just shuffles data around in the same memory pool. The result is ~5% GPU utilization and dramatically slower generation.
Wrong:
launch:args: ["--lowvram"] # 5% GPU util on APU
Right:
# Let the default memory management handle it.# On APU, smart memory with CPU text encoder is optimal.launch:args: []
Key Takeaways
- Use conditional patches for GPU-specific config — never hardcode vendor paths
- Always include a health check with enough retries for model loading
- Mark critical models as models_required: true; optional ones as false
- Use BF16 on AMD GPUs — FP16 causes NaN in attention layers
- Use setsid() (new_session: true) for GUI apps, not process_group
- Never use --lowvram on APU hardware — it shuffles data in the same RAM