# SPEC-inventory: Inventar, Modell-Katalog, Placement Paket: `knaster.inventory`. CLI: `knaster inventory collect`, `knaster placement plan`. ## 1. Node-Profil ```yaml name: pve-ada cpu: {model: "...", cores: 8, threads: 16} memory_gb: 64 disks: [{name: nvme0n1, size_gb: 256, rotational: false}] gpus: - {index: 0, name: "NVIDIA RTX 4000 Ada Generation", memory_gb: 20, compute_cap: 8.9, driver: "..."} ``` Datenquellen: `nvidia-smi --query-gpu=index,name,memory.total,compute_cap,driver_version --format=csv,noheader,nounits`, `/proc/meminfo`, `/proc/cpuinfo` bzw. `lscpu`, `lsblk -J -b -d -o NAME,SIZE,ROTA`. Die Parser sind reine Funktionen auf dem jeweiligen Text und testbar. `collect` ruft die Befehle lokal auf. ## 2. Katalog (`catalog/models.yaml`, `catalog/roles.yaml`) Engines (`models.yaml → engines`) setzen Untergrenzen für die Compute Capability, die für alle ihre Modelle gelten (z. B. `pytorch ≥ 7.5`). GPUs mit `disabled: true` im Inventar ignoriert das Placement und listet sie unter `disabled_gpus`. Ein Modell hat `kind` (llm, embedding, reranker, tts), `vram_gb` (Gewichte plus Mindest-KV-Cache), `min_cc`, `engines`, `context`, `lora`. Eine Rolle hat `needs` (`engine`, `min_vram_gb`, `min_cc`, `max_cc?`, `gpu: true|false`), `prefer` (z. B. `smallest_fitting`), `count` und `slots`. ## 3. Placement (`plan(nodes, roles, models) -> PlacementPlan`) Deterministisch: 1. Alle GPUs aller Nodes zu einer Liste `(node, gpu)` zusammenfassen. 2. Rollen nach `priority` (aufsteigend) abarbeiten. Für jede Rolle werden `count` GPUs gesucht, die `needs` erfüllen und noch frei sind. - `prefer: largest` wählt die GPU mit dem meisten VRAM (für LLM-Rollen). - `prefer: smallest_fitting` wählt die kleinste passende GPU (für Embedding und Rerank). So bleiben große Karten frei. 3. Rollen mit `share_with: ` teilen sich die GPU (bzw. bei `gpu: false` den Node) einer bereits platzierten Rolle. Ein Beispiel ist TTS auf `gpu-flex`. 4. Rollen mit `gpu: false` bzw. `cpu_fallback: true` werden ohne passende GPU den CPU-Nodes zugewiesen, sortiert nach RAM. Nodes mit `cpu_roles: false` (Arbeitsplätze, Kiosk) sind davon ausgenommen. Dort wird nur die eigene GPU verplant. 5. Pro zugewiesener Rolle werden die Katalogmodelle gelistet, die passen (Engine, VRAM, CC). 6. Ergebnis: `assignments[{role, node, gpu_index?, models_fitting[]}]` und `unplaced[{role, reason}]`. Der Plan ist der Input für `platform/proxmox` (welche VM-Rolle auf welchem Host mit welchem Resource Mapping) und für die Registry (welche Slots existieren).