~12 min read

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
yaml
# .thumper.yaml — GPU fallback chain
gpu:
required: false
preferred_backends: [cuda, rocm, mps, cpu]
patches:
- name: cuda-flags
condition: { gpu_vendor: nvidia }
env:
CUDA_VISIBLE_DEVICES: "0"
TORCH_DTYPE: "float16"
- name: rocm-flags
condition: { gpu_vendor: amd }
env:
HSA_OVERRIDE_GFX_VERSION: "11.0.0"
TORCH_DTYPE: "bfloat16"
- name: cpu-fallback
condition: { gpu_vendor: none }
env:
FORCE_CPU: "1"
The launcher evaluates conditions top-to-bottom and applies the first matching patch. Always put the most specific condition first and CPU last.

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.

yaml
# .thumper.yaml — Ollama auto-start
dependencies:
- name: ollama
auto_start: true
ollama_port_override: 11435
models:
- 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.

The ollama_port_override prevents conflicts when the user already has a system Ollama running on the default port 11434.

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.

yaml
# pack.yaml — SDXL Starter Pack
name: sdxl-starter
version: "1.0.0"
models:
- ref: sdxl-base-v1.0
models_required: true
slot: checkpoint
- ref: sdxl-vae-fp16
models_required: true
slot: vae
- ref: sdxl-refiner-v1.0
models_required: false
slot: 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.

yaml
# .thumper.yaml — health check with backoff
health_check:
url: "http://127.0.0.1:8188/system_stats"
retries: 30
interval: "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.

If you omit the health check entirely, the launcher marks the app as "Running" immediately after process start — even if the app is still loading models and is not ready to accept requests.

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.

yaml
# .thumper.yaml — patch layering
patches:
# Base — applies everywhere
- name: base-config
env:
LOG_LEVEL: "info"
MAX_WORKERS: "4"
# GPU vendor — overrides base
- name: amd-perf
condition: { gpu_vendor: amd }
env:
MIOPEN_FIND_MODE: "2"
PYTORCH_HIP_ALLOC_CONF: "expandable_segments:True"
# OS-specific — filesystem paths
- name: linux-paths
condition: { 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.

yaml
# model.yaml — resumable download config
files:
- 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.

Always include sha256 in your model manifest. Without it, corrupted downloads cannot be detected and the app may crash with cryptic errors during model loading.

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:

yaml
env:
LD_LIBRARY_PATH: "/usr/lib/cuda/lib64"

Right:

yaml
patches:
- name: cuda-libs
condition: { 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:

yaml
# No health_check section at all
launch:
command: "python main.py"

Right:

yaml
launch:
command: "python main.py"
health_check:
url: "http://127.0.0.1:8080/health"
retries: 30
interval: "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:

yaml
env:
TORCH_DTYPE: "float16" # NaN on AMD APU!

Right:

yaml
patches:
- name: amd-precision
condition: { 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:

yaml
launch:
process_group: true # SIGTSTP kills Electron apps

Right:

yaml
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:

yaml
# All models on GPU — OOM during VAE stage
env:
DEVICE: "cuda"

Right:

yaml
patches:
- name: apu-memory
condition: { 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:

yaml
launch:
args: ["--lowvram"] # 5% GPU util on APU

Right:

yaml
# 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