---
name: llama-cpp
description: llama.cpp local GGUF inference + HF Hub model discovery.
version: 2.1.3
author: Orchestra Research
license: MIT
dependencies: [llama-cpp-python>=0.2.0]
platforms: [linux, macos, windows]
metadata:
  hermes:
    tags: [llama.cpp, GGUF, Quantization, Hugging Face Hub, CPU Inference, Apple Silicon, Edge Deployment, AMD GPUs, Intel GPUs, NVIDIA, URL-first]
---

# llama.cpp + GGUF

Use this skill for local GGUF inference, quant selection, or Hugging Face repo discovery for llama.cpp.

## When to use

- Run local models on CPU, Apple Silicon, CUDA, ROCm, or Intel GPUs
- Find the right GGUF for a specific Hugging Face repo
- Build a `llama-server` or `llama-cli` command from the Hub
- Search the Hub for models that already support llama.cpp
- Enumerate available `.gguf` files and sizes for a repo
- Decide between Q4/Q5/Q6/IQ variants for the user's RAM or VRAM

## Model Discovery workflow

Prefer URL workflows before asking for `hf`, Python, or custom scripts.

1. Search for candidate repos on the Hub:
   - Base: `https://huggingface.co/models?apps=llama.cpp&sort=trending`
   - Add `search=<term>` for a model family
   - Add `num_parameters=min:0,max:24B` or similar when the user has size constraints
2. Open the repo with the llama.cpp local-app view:
   - `https://huggingface.co/<repo>?local-app=llama.cpp`
   - When multiple providers offer the same model, compare download counts at `https://huggingface.co/api/models?search=<model>&sort=downloads` and use the tree API on each repo to compare actual file sizes (see `references/cross-provider-comparison.md`)
3. Treat the local-app snippet as the source of truth when it is visible:
   - copy the exact `llama-server` or `llama-cli` command
   - report the recommended quant exactly as HF shows it
4. Read the same `?local-app=llama.cpp` URL as page text or HTML and extract the section under `Hardware compatibility`:
   - prefer its exact quant labels and sizes over generic tables
   - keep repo-specific labels such as `UD-Q4_K_M` or `IQ4_NL_XL`
   - if that section is not visible in the fetched page source, say so and fall back to the tree API plus generic quant guidance
5. Query the tree API to confirm what actually exists:
   - `https://huggingface.co/api/models/<repo>/tree/main?recursive=true`
   - keep entries where `type` is `file` and `path` ends with `.gguf`
   - use `path` and `size` as the source of truth for filenames and byte sizes
   - separate quantized checkpoints from `mmproj-*.gguf` projector files and `BF16/` shard files
   - use `https://huggingface.co/<repo>/tree/main` only as a human fallback
6. If the local-app snippet is not text-visible, reconstruct the command from the repo plus the chosen quant:
   - shorthand quant selection: `llama-server -hf <repo>:<QUANT>`
   - exact-file fallback: `llama-server --hf-repo <repo> --hf-file <filename.gguf>`
7. Only suggest conversion from Transformers weights if the repo does not already expose GGUF files.

## Quick start

### Install llama.cpp

```bash
# macOS / Linux (simplest)
brew install llama.cpp
```

```bash
winget install llama.cpp
```

```bash
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build
cmake --build build --config Release
```

### Install from source with CUDA (Debian / GCC 14)

Building with CUDA on Debian with GCC 14 requires a compatibility workaround — CUDA 12.x `nvcc` rejects GCC >13.

**Before updating, always backup existing binaries:**

```bash
# Backup to source tree for future reference
mkdir -p ~/src/llama.cpp/backups-sm61
sudo cp /usr/local/bin/llama-server /usr/local/bin/llama-server.bak \
        /usr/local/bin/llama-server-turbo /usr/local/bin/llama-server-turbo.bak \
        ~/src/llama.cpp/backups-sm61/
```

**CUDA 12.6 with nvcc not on PATH (Debian Hermes host):**

When CUDA toolkit is at `/usr/local/cuda-12.6` and nvcc isn't in `PATH`, cmake's `enable_language(CUDA)` fails because it can't find the compiler. Set all three:

```bash
CUDAHOSTCXX=/usr/bin/g++-13 cmake .. \
  -DCMAKE_C_COMPILER=/usr/bin/gcc-13 \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_COMPILER=/usr/local/cuda-12.6/bin/nvcc \
  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/g++-13 \
  -DCMAKE_CUDA_ARCHITECTURES=75 \
  -DGGML_CUDA=ON \
  -DGGML_CUDA_FA=ON \
  -DGGML_CUDA_GRAPHS=ON \
  -DGGML_CPU=ON \
  -DGGML_OPENMP=ON \
  -DGGML_NATIVE=ON \
  -DGGML_LLAMAFILE=ON \
  -DGGML_BUILD_EXAMPLES=OFF \
  -DGGML_BUILD_TESTS=OFF \
  -DGGML_CCACHE=OFF \
  -DCMAKE_BUILD_TYPE=Release
```

The key difference from the simpler `CUDAHOSTCXX=...` variant is that when nvcc isn't discoverable via `PATH`, cmake needs `CMAKE_CUDA_COMPILER` (to find nvcc) AND `CMAKE_CUDA_HOST_COMPILER` (to tell nvcc which g++ to use). `CUDAHOSTCXX` alone only works if cmake can already find nvcc.

**Cmake flag migration (upstream change around May 2026):** Upstream ggml-org renamed cmake flags from `GGML_CUDA`/`GGML_CUDA_FA` etc. to `LLAMA_CUDA`/`LLAMA_CUDA_FA`. If `-DGGML_CUDA=ON` is silently ignored during cmake configuration (the flag shows up as unused in cache), the build used the newer `LLAMA_*` prefix. Run `cmake -LAH 2>/dev/null | grep -E "LLAMA_CUDA|GGML_CUDA"` on a configured build dir to check which set is active. Forks (EsmaeelNabil MTP-TurboQuant, BoFan MTP-TurboQuant) still use the `GGML_*` prefix as of June 2026.

**Clone and build — preferred (static, self-contained):**

```bash
git clone https://github.com/ggml-org/llama.cpp /tmp/llama.cpp
cd /tmp/llama.cpp && mkdir -p build && cd build

CUDAHOSTCXX=/usr/bin/gcc-13 cmake .. \
  -DGGML_CUDA=ON \
  -DGGML_CUDA_FA=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DCUDAToolkit_ROOT=/usr/local/cuda \
  -DBUILD_SHARED_LIBS=OFF    # ⚠️ Required for static binary

cmake --build . --target llama-server --config Release -j$(nproc)

# Install (keep backups just in case)
sudo cp bin/llama-server /usr/local/bin/llama-server-cuda
```

`BUILD_SHARED_LIBS=OFF` produces a fully static 100+ MB binary. Without it, cmake may default to a 9 MB dynamically-linked binary that depends on `.so` files from the build tree (`libllama.so`, `libggml-cuda.so`, etc.) — if `/tmp/llama.cpp/` gets cleaned up later, the installed binary silently fails.

**Clone and build — fallback (CUDAHOSTCXX only, may produce dynamic binary):**

```bash
git clone https://github.com/ggml-org/llama.cpp /tmp/llama.cpp
cd /tmp/llama.cpp && mkdir -p build && cd build

# Create nvcc wrapper with GCC 13 compatibility
cat > /tmp/nvcc-wrapper.sh << 'WRAPPER'
#!/bin/bash
exec /usr/local/cuda/bin/nvcc -allow-unsupported-compiler -ccbin /usr/bin/gcc-13 "$@"
WRAPPER
chmod +x /tmp/nvcc-wrapper.sh

cmake .. \
  -DGGML_CUDA=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_CUDA_COMPILER=/tmp/nvcc-wrapper.sh \
  -DCUDAToolkit_ROOT=/usr/local/cuda

cmake --build . --target llama-server --config Release -j$(nproc)

# Install (keep backups just in case)
sudo cp bin/llama-server /usr/local/bin/llama-server-cuda
```

**Method 2 — CUDAHOSTCXX env var (simpler):**

For older fork checkouts where cmake may not find CUDA, set the env var directly instead of using a wrapper:

```bash
cd /tmp/llama.cpp && mkdir -p build && cd build
CUDAHOSTCXX=/usr/bin/gcc-13 cmake .. \
  -DGGML_CUDA=ON \
  -DGGML_CUDA_FA=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DCUDAToolkit_ROOT=/usr/local/cuda
cmake --build . --target llama-server --config Release -j$(nproc)
```

This works because `CUDAHOSTCXX` tells nvcc which host compiler to use, bypassing the gcc version check without needing a shell wrapper.

**Verify the new build:**

```bash
/usr/local/bin/llama-server-cuda --version
# Output: version: 1 (XXXXXXX) — new commit hash
```

**KV cache type note:** The default `llama-server` binary (BoFan's MTP-TurboQuant fork) supports TurboQuant KV cache types: `turbo2`, `turbo3`, `turbo4`. Upstream ggml-org builds do NOT have these — they only support `f32`, `f16`, `bf16`, `q8_0`, `q4_0`, `q4_1`, `iq4_nl`, `q5_0`, `q5_1`. Use `f16` or `iq4_nl` as TurboQuant replacements on vanilla builds.

**TurboQuant KV cache (turbo2/turbo3/turbo4):** Google Research's KV cache compression (ICLR 2026) using PolarQuant + QJL. ~2-4x compression. Default in the installed `llama-server`. Recommended flags: `-ctk turbo4 -ctv turbo2`.

**Pascal + TurboQuant Flash Attention interaction (important):** On Ray's current `/usr/local/bin/llama-server` build (`3c7616b`, BoFan TurboQuant fork), Flash Attention is often auto-enabled on GTX 1080 Ti (CC 6.1), and TurboQuant KV can require it. In the Qwen3.6-35B-A3B benchmark, the log showed:
```text
llama_init_from_model: turbo cache types require flash_attn — enabling automatically
llama_context: flash_attn    = enabled
```
This happened even though the command passed `-fa off`. Dense-model logs for Qwen3-14B, Qwen3.5-9B, DeepSeek-R1-8B, Gemma 3, Gemma 4, and Ministral also showed Flash Attention auto-enabled. Practical rule: with TurboQuant KV, trust the server log over the CLI flag and default to omitted/`auto` unless you are explicitly benchmarking a non-TurboQuant path.

**Qwen3 8B/14B long context:** Qwen3 config.json shows `max_position_embeddings: 40960` (40K native) with `rope_theta: 1000000` and no RoPE scaling. For Hermes' 65K minimum on dense Qwen3 models, use llama.cpp's YaRN flags:
```bash
--rope-scaling yarn --rope-scale 1.6 --yarn-orig-ctx 40960 \
-c 65536 --ctx-size 65536
```
For 128K, use `--rope-scale 3.2` with `--yarn-orig-ctx 40960`. This is aggressive (3.2x extrapolation) — quality may degrade at the far end, but many reports confirm it works. Test before committing.

**Qwen thinking-mode blank-content pitfall:** Hybrid-thinking Qwen-family GGUFs may return empty `message.content` and put text under `reasoning_content` when thinking is enabled. If the consumer expects OpenAI `message.content` (Hermes/gateway/tools), add:
```bash
--chat-template-kwargs '{"enable_thinking":false}'
```
Retest with `/v1/chat/completions`; this fixed Qwen3.5-9B uncensored returning blank content while text completions worked.

**Fork status (updated May 2026):**
- **EsmaeelNabil/llama.cpp-mtp-turbo-quant** (Debian Hermes host, RTX 2080 Ti) — all-in-one merge of MTP + TurboQuant, branch `feat/mtp-turboquant-kv-cache`. Based on the newest upstream (May 12, commit `a578bb6b`). Turbo2/3/4 KV cache types, CUDA FA kernels for all turbo combinations, MTP speculative decoding (`--spec-type mtp`). Conflict-resolved merge of am17an MTP + TheTom TurboQuant.
- **BoFan-tunning/llama.cpp-MTP-TurboQuant** (Ray's CachyOS machine, GTX 1080 Ti) — based on ~May 4 upstream, MTP fused, crash fixes, works with SWA (Gemma 3/4 ✅), no RDNA2 baggage
- **Stormrage34/llama.cpp-turboquant-hip** (legacy) — has RDNA2 baggage, SWA models hang, base too old for Gemma 3. Even the pre-RDNA2 commit (`ba62fc7`) crashes Gemma 3 (SIGSEGV, base too old)

**Which fork on which machine:** Debian Hermes host (RTX 2080 Ti, sm_75) → EsmaeelNabil. Ray's CachyOS (GTX 1080 Ti, sm_61) → BoFan. Different SM targets, different fork bases — don't cross-install.

**Running two builds side by side:** When you need MTP support for a new model architecture (e.g. Gemma 4 QAT's `gemma4-assistant` MTP drafter, added Jun 7 PR #23398) but also want to keep an existing fork's features (TurboQuant KV cache), build a fresh upstream binary alongside the fork. Clone from `ggml-org/llama.cpp`, build with `cmake -DLLAMA_CUDA=ON` (new prefix), and install as a separate binary like `llama-server-upstream`. Use it only for the models that need the newer arch support. The fork handles the rest. This avoids messy cherry-pick conflicts across divergent codebases.

Build recipe (static binary): `BUILD_SHARED_LIBS=OFF` + `CUDAHOSTCXX=/usr/bin/gcc-13`. For CUDA 12.6 where nvcc isn't on PATH, also set `CMAKE_CUDA_COMPILER` and `CMAKE_CUDA_HOST_COMPILER` explicitly. See `references/turboquant.md` for full build instructions, fork comparison, compatibility table, and known issues.

### Run directly from the Hugging Face Hub

```bash
llama-cli -hf bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0
```

```bash
llama-server -hf bartowski/Llama-3.2-3B-Instruct-GGUF:Q8_0
```

### Run an exact GGUF file from the Hub

Use this when the tree API shows custom file naming or the exact HF snippet is missing.

```bash
llama-server \
    --hf-repo microsoft/Phi-3-mini-4k-instruct-gguf \
    --hf-file Phi-3-mini-4k-instruct-q4.gguf \
    -c 4096
```

### OpenAI-compatible server check

```bash
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "Write a limerick about Python exceptions"}
    ]
  }'
```

## Python bindings (llama-cpp-python)

`pip install llama-cpp-python` (CUDA: `CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python --force-reinstall --no-cache-dir`; Metal: `CMAKE_ARGS="-DGGML_METAL=on" ...`).

### Basic generation

```python
from llama_cpp import Llama

llm = Llama(
    model_path="./model-q4_k_m.gguf",
    n_ctx=4096,
    n_gpu_layers=35,     # 0 for CPU, 99 to offload everything
    n_threads=8,
)

out = llm("What is machine learning?", max_tokens=256, temperature=0.7)
print(out["choices"][0]["text"])
```

### Chat + streaming

```python
llm = Llama(
    model_path="./model-q4_k_m.gguf",
    n_ctx=4096,
    n_gpu_layers=35,
    chat_format="llama-3",   # or "chatml", "mistral", etc.
)

resp = llm.create_chat_completion(
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is Python?"},
    ],
    max_tokens=256,
)
print(resp["choices"][0]["message"]["content"])

# Streaming
for chunk in llm("Explain quantum computing:", max_tokens=256, stream=True):
    print(chunk["choices"][0]["text"], end="", flush=True)
```

### Embeddings

```python
llm = Llama(model_path="./model-q4_k_m.gguf", embedding=True, n_gpu_layers=35)
vec = llm.embed("This is a test sentence.")
print(f"Embedding dimension: {len(vec)}")
```

You can also load a GGUF straight from the Hub:

```python
llm = Llama.from_pretrained(
    repo_id="bartowski/Llama-3.2-3B-Instruct-GGUF",
    filename="*Q4_K_M.gguf",
    n_gpu_layers=35,
)
```

## Choosing a quant

Use the Hub page first, generic heuristics second.

- Prefer the exact quant that HF marks as compatible for the user's hardware profile.
- For general chat, start with `Q4_K_M`.
- For code or technical work, prefer `Q5_K_M` or `Q6_K` if memory allows.
- For very tight RAM budgets, consider `Q3_K_M`, `IQ` variants, or `Q2` variants only if the user explicitly prioritizes fit over quality.
- For multimodal repos, mention `mmproj-*.gguf` separately. The projector is not the main model file.
- Do not normalize repo-native labels. If the page says `UD-Q4_K_M`, report `UD-Q4_K_M`.

## Extracting available GGUFs from a repo

When the user asks what GGUFs exist, return:

- filename
- file size
- quant label
- whether it is a main model or an auxiliary projector

Ignore unless requested:

- README
- BF16 shard files
- imatrix blobs or calibration artifacts

Use the tree API for this step:

- `https://huggingface.co/api/models/<repo>/tree/main?recursive=true`

For a repo like `unsloth/Qwen3.6-35B-A3B-GGUF`, the local-app page can show quant chips such as `UD-Q4_K_M`, `UD-Q5_K_M`, `UD-Q6_K`, and `Q8_0`, while the tree API exposes exact file paths such as `Qwen3.6-35B-A3B-UD-Q4_K_M.gguf` and `Qwen3.6-35B-A3B-Q8_0.gguf` with byte sizes. Use the tree API to turn a quant label into an exact filename.

## Search patterns

Use these URL shapes directly:

```text
https://huggingface.co/models?apps=llama.cpp&sort=trending
https://huggingface.co/models?search=<term>&apps=llama.cpp&sort=trending
https://huggingface.co/models?search=<term>&apps=llama.cpp&num_parameters=min:0,max:24B&sort=trending
https://huggingface.co/<repo>?local-app=llama.cpp
https://huggingface.co/api/models/<repo>/tree/main?recursive=true
https://huggingface.co/<repo>/tree/main
```

## Output format

When answering discovery requests, prefer a compact structured result like:

```text
Repo: <repo>
Recommended quant from HF: <label> (<size>)
llama-server: <command>
Other GGUFs:
- <filename> - <size>
- <filename> - <size>
Source URLs:
- <local-app URL>
- <tree API URL>
```

## Ray-specific long-context benchmarking rule

When benchmarking or recommending `llama-server` flags for Ray's GTX 1080 Ti fleet, do **not** stop at short-context or ~10k prompt tests if the lineup is meant for 65k/100k/128k use.

Required workflow for this user:
- benchmark at the **operational context tier** for the model: usually **65k minimum**, **100k where plausible**, and **128k** only when the model/service claims it and fit is realistic
- test **multiple flag variants**, not one tuned profile
- cross-reference recommendations against **llama.cpp docs, GitHub issues/discussions, and community reports**, not just intuition
- in the final report, always show:
  - exact context tested
  - prompt tokens actually ingested
  - prompt tok/s
  - decode tok/s
  - the flag variants tested and which one won

Concrete long-context examples for Ray live in `references/high-context-flag-space-ray-1080ti.md`.

## References

- **[ray-local-model-fleet.md](references/ray-local-model-fleet.md)** — Ray-specific local GGUF fleet replacement checklist: `hf download`, service/model-switcher/config/Hindsight updates, Qwen3 YaRN flags, thinking-mode blank-content fix, verified current ports
- **[cross-provider-comparison.md](references/cross-provider-comparison.md)** — Compare same-model GGUFs across providers (Unsloth, Google, LM Studio), get accurate file sizes from xet-storage repos via the tree API, VRAM fit analysis per GPU, and cross-provider quant comparison
- **[flag-design-guide.md](references/flag-design-guide.md)** — VRAM math, MoE-vs-dense decision tree, context sizing heuristics, per-model flag tables, threading strategy — design optimal llama-server flags for any GGUF model on your hardware
- **[hub-discovery.md](references/hub-discovery.md)** - URL-only Hugging Face workflows, search patterns, GGUF extraction, and command reconstruction
- **[advanced-usage.md](references/advanced-usage.md)** — speculative decoding, batched inference, grammar-constrained generation, LoRA, multi-GPU, custom builds, benchmark scripts
- **[quantization.md](references/quantization.md)** — quant quality tradeoffs, when to use Q4/Q5/Q6/IQ, model size scaling, imatrix
- **[server.md](references/server.md)** — direct-from-Hub server launch, OpenAI API endpoints, Docker deployment, NGINX load balancing, monitoring
- **[optimization.md](references/optimization.md)** — CPU threading, BLAS, GPU offload heuristics, batch tuning, benchmarks, systematic benchmarking workflow (test don't theorize)
- **[troubleshooting.md](references/troubleshooting.md)** — install/convert/quantize/inference/server issues, Apple Silicon, debugging
- **[hung-server-diagnosis.md](references/hung-server-diagnosis.md)** — diagnose hung llama-server (high CPU, accepts TCP but never responds), root causes, and fix
- **[qwen3.6-deltanet.md](references/qwen3.6-deltanet.md)** — Qwen3.6-27B DeltaNet architecture: layer structure, MTP variant limitations, VRAM fitment, recommended flags, comparison vs MoE models
- **[llama-swap.md](references/llama-swap.md)** — llama-swap auto-swapping proxy: replaces individual systemd services + swap scripts with a single binary that starts/stops models on demand. Recommended for multi-model setups.
- **[multi-model-hot-swap.md](references/multi-model-hot-swap.md)** — full guide: systemd services, Hermes config, sudoers setup, model-switcher script (legacy approach; prefer llama-swap)
- **[gemma-4-moe-vision.md](references/gemma-4-moe-vision.md)** — Gemma 4 26B-A4B MoE with vision: architecture, VRAM, flags, speed benchmarks, Qwen 35B comparison
- **[turboquant.md](references/turboquant.md)** — TurboQuant KV cache compression (turbo2/3/4), Google Research paper, Stormrage34 fork, build instructions, known issues
- **[flash-attn-pascal-benchmark.md](references/flash-attn-pascal-benchmark.md)** — GTX 1080 Ti / Pascal validation of `--flash-attn on|off` on current build, with one-shot prompt/gen timing results and recommendation
- **[ray-fleet-benchmarks-1080ti.md](references/ray-fleet-benchmarks-1080ti.md)** — cross-fleet prompt/gen throughput, VRAM, and tuning conclusions for Ray's GTX 1080 Ti local model lineup
- **[benchmark-new-gguf-workflow.md](references/benchmark-new-gguf-workflow.md)** — full workflow: download GGUFs from HuggingFace with `curl -sL`, resume truncated parallel downloads, verify GGUF headers, speed-bench with llama-server log parsing, and interpret results
- **[ray-dense-vs-moe-downloads-1080ti.md](references/ray-dense-vs-moe-downloads-1080ti.md)** — why Qwen3.6-35B-A3B MoE outruns smaller dense models on Ray's 1080 Ti; download-quant heuristics and expected speed ranges for dense 24B/32B additions
- **[high-context-flag-space-ray-1080ti.md](references/high-context-flag-space-ray-1080ti.md)** — Ray-specific long-context benchmarking rules: test at 65k/100k/128k where applicable, compare multiple flag variants, and note the measured 100k Qwen3.6 batch-size result (4096/1024 beats 2048/512 on prefill while decode stays flat)
- **[gpu-architecture-upgrade.md](references/gpu-architecture-upgrade.md)** — GPU physical swap procedure, build inspection techniques (CMakeCache audit, `strings` for SM targets, binary size comparison), and SM architecture upgrade implications (Pascal → Turing tensor cores)
- **[model-switcher](templates/model-switcher)** — Python TUI script for interactive hot-swap (stop/start/config update/health check)
- **[frontend-integration.md](references/frontend-integration.md)** — Consuming llama.cpp servers from frontends: LibreChat (multi-custom-endpoint via Docker) and OpenCode (remote provider config via Tailscale/LAN) — port architecture, firewall rules, model ID discovery, end-to-end verification
- **[remote-switch.py](scripts/remote-switch.py)** — Generic Python script to remotely switch llama-server systemd services via SSH from another machine (customize SERVER/MODELS dict)

## Model Discovery: Research Community Impressions

When the user asks about a model's strengths, weaknesses, or which model to use for a task, DO NOT make up descriptions based only on model cards or parameter counts. The user expects research-backed community impressions.

**Research workflow:**

1. **HuggingFace discussions tab** — click `Discussions` on the model page. Sort by `Top` or `Latest`. Look for real user experiences, bug reports, quality complaints.

2. **HuggingFace likes & downloads** — number of ❤️ and download count are useful proxies. 1K+ ❤️ and 1M+ downloads = widely used and vetted.

3. **Reddit r/LocalLLaMA** — search for model name. Look for comparison threads ("X vs Y"), benchmark threads, and "what's your daily driver" type discussions. This is the most honest source of strengths/weaknesses.

4. **YouTube reviews from known testers** — search for model name + "local testing", "first look", or "benchmark". Watching dedicated reviews (23-minute testing videos, real app building demos) gives actual quality signal.

5. **GitHub/llama.cpp ecosystem** — if the llama.cpp team built tooling around a specific model (e.g., llama.vim Neovim plugin targeting Qwen2.5-Coder), that's a strong quality signal.

**When reporting back, include real community data:**
- ❤️ / download counts on HuggingFace
- Direct quotes from community (r/LocalLLaMA posts, YouTube comments)
- Known bugs or regressions users report
- What it's ACTUALLY good at vs what it struggles with
- How it compares to similar models at the same size

**Pitfall — model card vs reality:** A model card will say "best in class for X." The community discussions will tell you about the repetition bug, the tool-calling issues, and where it actually falls short. Always prioritize community experience over marketing copy.

## Multi-Model Hot-Swap

When running multiple local GGUF models with Hermes Agent, use separate systemd services on different ports and a swap script that orchestrates everything.

### Setup Overview

1. **One systemd service per model** — each on a unique port. Copy flags from your working service and change `--port` and `-m /path/to/model.gguf`. See `references/multi-model-hot-swap.md` for full templates.

2. **Register all models in Hermes** under a single `custom_providers:` entry called `local` in `~/.hermes/config.yaml`. List all models in the `models:` dict with their context_lengths. The swap script updates `model.default`, `model.provider` (always `custom:local`), and `model.base_url` (per-model port).

3. **(Optional) NOPASSWD sudoers** — add the specific `systemctl start/stop` commands to `/etc/sudoers.d/` so the swap script doesn't prompt for a password.

4. **Swap via the script** at `templates/model-switcher` — it stops the running model, starts the target, updates Hermes config, and waits for the new model's API to respond. Works interactively (TUI menu) or with a quick name argument (`models 9b`).

### Manual Commands

```bash
# Port map:
#   8081 = llama-server      (Qwen3.6-35B)
#   8082 = llama-server-9b   (Qwen3.5-9B)
#   8086 = llama-server-llama3 (Llama-3.2-3B)
#   8087 = llama-server-smol (SmolLM3-3B)
#   8088 = llama-server-phi4 (Phi-4 14B)
#   8089 = llama-server-gemma3 (Gemma 3 12B)
#   8090 = llama-server-gemma4 (Gemma 4 26B)

# Switch to 35B
sudo systemctl stop llama-server-9b.service
sudo systemctl start llama-server.service
hermes config set model.default Qwen3.6-35B-A3B-UD-Q4_K_M.gguf
hermes config set model.provider custom:local
hermes config set model.base_url http://127.0.0.1:8081/v1

# Switch to 9B
sudo systemctl stop llama-server.service
sudo systemctl start llama-server-9b.service
hermes config set model.default Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q4_K_M.gguf
hermes config set model.provider custom:local
hermes config set model.base_url http://127.0.0.1:8082/v1

# Switch to Phi-4
sudo systemctl stop llama-server.service
sudo systemctl start llama-server-phi4.service
hermes config set model.default phi-4-Q4_K.gguf
hermes config set model.provider custom:local
hermes config set model.base_url http://127.0.0.1:8088/v1
```

### Key Pitfalls

- **Each model needs a unique port** — they cannot share.
- **MoE flags are model-specific.** `--n-cpu-moe` only applies to Mixture-of-Experts models. Do NOT copy it blindly to non-MoE models or they will refuse to load.
- **Stop before starting** — Hermes only talks to one provider at a time. Always stop the old server before starting the new one.
- **VRAM drain delay between stop and start:** When stopping one model and immediately starting another, the NVIDIA driver may not have fully reclaimed the old model's VRAM. Large dense models (8+ GB) or MoE models can take 5-15s to fully release VRAM after `systemctl stop`. If the new service starts during this window, it may crash or hang trying to allocate VRAM that isn't actually free yet. **Workaround:** Add a 5-10s sleep between stop and start in swap scripts, or poll `nvidia-smi` for VRAM to drop before starting.
- **Cloud switch keeps local warm:** When switching FROM a local model TO a cloud model (DeepSeek, OpenRouter, Codex), the auto-model-switch.py path watcher does NOT stop the local service. The local model stays loaded in VRAM so switching back is instant. This is correct behavior — do NOT stop local services when going to cloud. Only stop local when going to another local.
- **Verify readiness** after swap: `curl http://localhost:<port>/v1/models` or the swap script does this automatically.
- **Session restart needed.** After switching the Hermes provider config, run `/reset` in CLI or `/restart` on the gateway for the change to take effect. The running conversation continues with the previously set model until the next session.
- **Consolidated provider gotcha:** If you use a single `custom:local` provider for all models, the swap script's `get_current_config()` must match on `model.default` (the GGUF filename), not `model.provider` (always `custom:local`). The template script handles this; a script written for the old pattern (matching on provider names like `custom:Qwen3.6-35B`) will break.

## 1-bit (Q1_0) Models — PrismML Fork

1-bit quantized models (Q1_0, like Bonsai-8B) require the **PrismML fork** of llama.cpp ([PrismML-Eng/llama.cpp](https://github.com/PrismML-Eng/llama.cpp), `prism` branch) which adds Q1_0 type definitions and CUDA kernels. Upstream ggml-org does not support Q1_0.

**Key facts:** b8846-d104cf1b6 (GCC 11.4.0, 696 commits behind master), CUDA 12.4/12.8 pre-built binaries, sm_50-80, 150 t/s at ~1 GB VRAM on 2080 Ti, 65K native context.

**Usage:** When deployed via llama-swap, ALWAYS use `llama-server-prism-wrapper` (which sets `LD_LIBRARY_PATH=/usr/local/lib/prism`) rather than calling `llama-server-prism` directly. **DO NOT set LD_LIBRARY_PATH globally** via systemd drop-in — this breaks all sm75 models by making them load incompatible prism libraries (b8846) instead of their own (b9341), causing SIGSEGV on spawn. The wrapper handles the library path per-model and is safe.

## QAT (Quantization-Aware Training) Models

QAT models are base models fine-tuned with QAT then quantized to GGUF — near-bf16 quality at lower bitrates.

### QAT vs non-QAT size on RTX 2080 Ti (11GB)

- **12B dense:** non-QAT Q4_K_M = 6.7 GB → QAT UD-Q4_K_XL = **6.26 GB** (-0.44 GB)
- **26B MoE:** non-QAT Q4_K_M = 16 GB → QAT UD-Q4_K_XL = **14 GB** (-2 GB)
- **26B MoE VRAM:** non-QAT 9.0 GB @ 4K → QAT **7.3 GB** (-1.7 GB) with same 35+ t/s

### MoE QAT VRAM math — file size ≠ VRAM

MoE models do NOT load the full file into VRAM. With `--n-cpu-moe`, only attention/router layers go to GPU (~7 GB for QAT 26B). Expert weights stay in CPU repack buffers. Always compute VRAM = shared_weights + embed + attention + KV_cache (not total_file_size).

### MTP with Gemma 4 QAT — build version matters

Gemma 4 QAT ships an MTP drafter (`gemma4-assistant` arch). Build b9341 does NOT support it — "unknown model architecture" error. Needs llama.cpp build b9500+ (upstream ggml-org, post-Jun 7 commit `#23398` by am17an: "llama : add Gemma4 MTP"). Use `--spec-type mtp` (not `draft-mtp`) on b9341-era builds. Run without MTP until you update the build. The `draft-mtp` spec type was added in a newer build — b9341 only knows `mtp`, `none`, `eagle3`.

### Gemma 4 QAT model sources

- **Unsloth** (`unsloth/gemma-4-12B-it-qat-GGUF`, `unsloth/gemma-4-26B-A4B-it-qat-GGUF`) — UD-Q4_K_XL format (Unsloth Dynamic 2.0, mixed quant, higher quality per byte)
- **Google official** (`google/gemma-4-12B-it-qat-q4_0-gguf`, `google/gemma-4-26B-A4B-it-qat-q4_0-gguf`) — Q4_0 only
- **LM Studio Community** (`lmstudio-community/gemma-4-12B-it-QAT-GGUF`) — Q4_0 only

Unsloth UD-Q4_K_XL is recommended: better quality per byte and smaller file size.

### Key Pitfalls

- **Systemd LD_LIBRARY_PATH breakage:** Do NOT set `LD_LIBRARY_PATH=/usr/local/lib/prism` globally via systemd drop-in (`/etc/systemd/system/llama-swap.service.d/env.conf`). This makes ALL sm75 child processes load incompatible prism libraries (b8846) instead of their own (b9341), causing SIGSEGV within 250ms of spawn. Instead, let `llama-server-prism-wrapper` set LD_LIBRARY_PATH per-model.
- **Stray llama-server processes hold VRAM:** After killing llama-swap, orphaned child processes keep CUDA memory allocated — `nvidia-smi` shows no running processes but VRAM is locked. Fix: `sudo rmmod nvidia_uvm && sudo modprobe nvidia_uvm` clears leaked CUDA contexts. Find orphans with `sudo lsof /dev/nvidia* | grep llama`.
- **llama-swap `--spec-type draft-mtp` vs `mtp`:** b9341-era builds use `--spec-type mtp`. Newer builds (post-Jun 7) may use `--spec-type draft-mtp`. Check with `llama-server --help | grep spec-type` to see which your binary supports before putting it in the config.

## Key Pitfalls

- **MoE flags are model-specific.** `--n-cpu-moe` only applies to Mixture-of-Experts models. Do NOT copy it blindly to non-MoE models or they will refuse to load.
- **`turbo4` KV cache default binary:** The installed `llama-server` (BoFan MTP-TurboQuant fork) has `turbo2/turbo3/turbo4` as native KV cache types. Upstream ggml-org builds do NOT have these — see `references/turboquant.md` for fork comparison. Recommended: `-ctk turbo4 -ctv turbo2`.
- **Dynamically linked binary trap:** Newer llama.cpp cmake defaults may produce a small (9-10 MB) dynamically-linked binary that depends on `.so` files from the build tree (`libllama.so`, `libggml-cuda.so`, etc.). If the build tree is later cleaned up (e.g., `/tmp/llama.cpp/` is tmpwatch'd), the installed binary silently fails. Always pass `-DBUILD_SHARED_LIBS=OFF` to cmake for a full static build. Check with `ldd` before installing to a permanent path — a static binary shows no llama/ggml library dependencies.
- **Qwen3.6-27B dense (DeltaNet architecture):** Uses `qwen35` arch in GGUF. For MTP support, use the **BoFan MTP-TurboQuant fork** (`merge-mtp-turboquant` branch) which properly handles `qwen35.cpp` MTP layer subtraction. See `references/turboquant.md`. For vanilla ggml-org: the MTP variant has 65 layers and llama.cpp's `recurrent_layer_arr` calculation doesn't account for MTP prediction layers, causing a `missing tensor blk.64.ssm_conv1d.weight` error. **Use the non-MTP variant** (64 layers) which loads cleanly. To fix MTP in vanilla: adjust `recurrent_layer_arr` loop to subtract `nextn_predict_layers` from effective layer count and add `nextn.*` tensor loading with `TENSOR_NOT_REQUIRED` for prediction head layers.
- **GPU upgrade requires llama.cpp rebuild:** When physically swapping GPUs (e.g., GTX 1080 Ti → RTX 2080 Ti), the NVIDIA driver auto-detects the new card — no driver reinstall needed. But compiled CUDA binaries are SM-architecture-locked. An `llama-server` built for `sm_61` will run on `sm_75` but tensor cores stay idle. Rebuild with `-DCMAKE_CUDA_ARCHITECTURES=75` (or your new SM version) to unlock the new hardware. See `references/gpu-architecture-upgrade.md` for the full inspection+rebuild procedure.
- **GCC 14 + CUDA incompatibility:** CUDA 12.4 nvcc rejects GCC >13. Fix: set `CUDAHOSTCXX=/usr/bin/gcc-13` as an env var before cmake. No wrapper script needed.
- **Flash Attention on Pascal (CC 6.1) is build-dependent — benchmark it, don't assume.** Older notes that GTX 1080 Ti rejects `--fa` are not durable. On Ray's current `/usr/local/bin/llama-server` build `3c7616b`, `--flash-attn on` is accepted on GTX 1080 Ti (compute capability 6.1) and the server logs `llama_context: flash_attn = enabled`. However, prompt/generation throughput on Qwen3-4B and Qwen3-8B was effectively a wash versus `--flash-attn off` (noise-level differences only). For older NVIDIA cards, test `on` vs `off` on the actual build/model/context combo before recommending a unit-file change; default to omitted/`auto` unless the benchmark shows a clear win. See `references/flash-attn-pascal-benchmark.md`.
- **`--no-mmap` + `--mlock` slowdown:** Together they make loading very slow for large models (9GB+ can take 60+ seconds). For quick tests, drop `--mlock`.
- **Remote access through firewall.** When consuming llama.cpp servers from another machine (OpenCode, LibreChat, etc.), see `references/frontend-integration.md` for UFW rules, client IP restrictions, Tailscale vs LAN connectivity, and model ID discovery. The `scripts/remote-switch.py` template shows how to control services remotely via SSH.
- **`fit off` needed for Stormrage TQ fork:** The Stormrage TQ fork's auto-fitting can hang on some models. Add `-fit off` when using `/usr/local/bin/llama-server-tq` to skip memory fitting. The old custom TQ build (commit 69d8e4b) doesn't support this flag.

## Resources

- **GitHub**: https://github.com/ggml-org/llama.cpp
- **Hugging Face GGUF + llama.cpp docs**: https://huggingface.co/docs/hub/gguf-llamacpp
- **Hugging Face Local Apps docs**: https://huggingface.co/docs/hub/main/local-apps
- **Hugging Face Local Agents docs**: https://huggingface.co/docs/hub/agents-local
- **Example local-app page**: https://huggingface.co/unsloth/Qwen3.6-35B-A3B-GGUF?local-app=llama.cpp
- **Example tree API**: https://huggingface.co/api/models/unsloth/Qwen3.6-35B-A3B-GGUF/tree/main?recursive=true
- **Example llama.cpp search**: https://huggingface.co/models?num_parameters=min:0,max:24B&apps=llama.cpp&sort=trending
- **License**: MIT
