Design + what exists so far · updated as build proceeds

Architecture

Design in one paragraph

llama.cpp built from current source with two backends — Vulkan (RADV) and HIP (ROCm gfx1151) — benchmarked head-to-head, winner per workload serves. Model weights live on the dedicated 2TB NVMe (/srv/llm/models). Multiple models serve side-by-side where memory allows (Qwen3.8-27B at 19 GB + DeepSeek-V4-Flash at 103 GB ≈ 121 GB co-resident; the 27B + a smaller endpoint otherwise), coordinated by llama-swap — the same tier/eviction design proven on our ashborn-prime node. One OpenAI-compatible endpoint (:8080) fronts everything; a small embeddings model gets a dedicated endpoint; the CPU reranker pattern carries over verbatim. Everything runs as user wg via systemd user units so it survives the dan account removal.

Why two backends

Layout on disk

/srv/llm/                     (owned by wg — survives dan-account removal)
├── src/llama.cpp/            source + build-vulkan/ + build-hip/
├── venv/                     Python 3.14 + huggingface_hub CLI (model pulls)
└── models/                   weights, one directory per model (2TB NVMe)
    └── Qwen3.8-27B-GGUF/     UD-Q4_K_XL + mmproj-F16 (vision) + MTP draft

The OS keeps its own 1TB NVMe; wiping/replacing models never touches it.

Carried over from ashborn-prime (proven config)

Endpoints (planned)

EndpointPurposeStatus
:8080 /v1OpenAI-compatible chat/completions front door (llama-swap)pending
:8080 /v1/embeddingsEmbedding model (separate small GGUF)model TBD
:18190 /v1/rerankCPU reranker (bge-reranker-v2-m3 Q8_0)pending
tailnet :22SSH admin (wg + admin key)live

Bound to the tailnet interface only — the LAN-facing firewalld zone stays closed beyond ssh/mdns.

Ownership & service model