# Mission Control Web-Dashboard zur Verwaltung eines **lokalen LLM-Stacks (`llama-swap`)** auf dem Bosgame M5. FastAPI-Backend + Svelte 5-Frontend (Vite-Build). **Leitprinzip: KISS — SoC ohne Overhead.** ## Architektur **Backend** (Top-Level-Helfer + ein Router je Bereich): - **`app.py`** — dünner Einstieg: `FastAPI`, hängt die Router ein, liefert das statische UI aus, Exception-Handler + `Cache-Control: no-cache`-Middleware. - **`config.py`** — alle Env-Vars + die gemeinsame `ruamel.yaml`-Instanz. Auch `SOURCE_DIR`/`PROD_DIR` fürs Self-Update. - **`auth.py`** — optionale Token-Auth: Header `X-MC-Token` **oder** Query `?token=` (Query ist Pflicht für WebSockets). - **`jobengine.py`** — In-Memory-Job-System (Threads + Subprocess) mit Live-Log. Secrets gehen über **stdin** (kein Leak in Log/`ps`). - **`llamaswap.py`** — spricht `llama-swap` an und liest/schreibt dessen `config.yaml` per `ruamel.yaml`. - **`hw_math.py`** — Odysseus-Fit-Mathe: VRAM/RAM-Bedarf, tps-Schätzung, `max_ctx_for`, `extract_params_b`. - **`recipes.py`** — kuratierte Use-Case-Stacks fürs Cookbook 2.0. - **`hermes_agent.py`** — Kern des Hermes-Agenten: Tool-Definitionen, Tool-Dispatcher, LLM-Loop (ReAct), Modell-Routing. - **`mcp_memory.py`** — stdio-MCP-Server: Gedächtnis-Tools für Cline/OpenCode/Claude Code. - **`routers/*.py`** — ein Router je Bereich: - `models.py` — status/download/register/update_model/unload/chat - `jobs.py` — Jobs-Liste - `maintenance.py` — update/self-update/os-update/service-restart/reboot/logs-WebSocket - `system.py` — status + stream-WebSocket (Live-Metriken psutil/sysfs) - `cookbook.py` — analyze/evaluate/recipes/install-recipe/upgrades - `integration.py` — test (Engine-Verbindungstest) - `news.py` — RSS-Aggregation via stdlib - `memory.py` — Gedächtnis-CRUD (SQLite, WAL-Mode), 5 Kategorien - `hermes.py` — Chat-WebSocket/transcribe(Whisper)/tts(Piper)/status/pubkey **Frontend** (`frontend/src/`, Svelte 5 + Vite, Build → `static/dist/`): - **`index.html`** — Gerüst: Sidebar-Nav (10 Tabs), Topbar, Alert-Banner, View-Container je Bereich. - **`frontend/src/main.ts`** — bootet alle Svelte-Panels, Topbar/Alert, WebSocket Live-Metriken, Polling. - **`frontend/src/panels/`** — je ein Panel: Overview, Models, Jobs(Aktivität), Server, Cookbook, Connect(Verbinden), News, Guides, Memory(Gedächtnis), Hermes. - **`frontend/src/stores/`** — Svelte 5 Runes: `status.svelte.ts`, `jobs.svelte.ts`, `system.svelte.ts`. - **Design-System (v3):** EINE Akzentfarbe Teal `#2dd4bf`. Grün/Gelb/Rot nur für Status. Tokens in `css/base.css`. ## Der Stack drumherum - **Bosgame M5**: AMD Strix Halo (gfx1151), Ubuntu 26.04, Kernel 7.0, ~124 GB GTT. LAN-IP `192.168.178.151`. - **Inferenz**: llama.cpp-ROCm-Binaries → `llama-swap` auf `*:8080` (LAN-offen, `-watch-config`). - **3 Modelle / 5 Rollen**: `coder` (Qwen3-30B-A3B), `scout` (Qwen3-8B), `vision` (Qwen3-VL). - **Mission Control**: Produktiv unter `/opt/mission-control`, Source unter `~/mission-control`. - **Gedächtnis**: SQLite unter `/srv/models/mission-control-memory.db` (5 Kategorien: user/instruction/stable/versioned/ephemeral). - **Hermes Agent**: läuft als Teil von Mission Control (kein separater Dienst), Voice via Whisper (CPU) + Piper TTS. ## Entwickeln & Deployen **Wo entwickelt wird:** Windows-PC (`F:\Coding Stuff\mission-control`), Ziel: Linux-Bosgame. Lokal nur Smoke-Test (rendert/bootet?), echter Funktionstest auf dem Bosgame. **Lokaler Smoke-Test (Windows):** ```bash python -m venv .venv && .venv/Scripts/python -m pip install -r requirements.txt .venv/Scripts/python -m uvicorn app:app --port 9001 ``` **Bosgame-Zugang:** ```bash ssh -i ~/.ssh/id_ed25519_hermes -o IdentitiesOnly=yes hitonabi@192.168.178.151 ``` User: `hitonabi`. sudo NOPASSWD-Whitelist für `systemctl restart mission-control|llama-swap` und `journalctl`. **Frontend-Build:** ```bash cd frontend && npm run build # vor jedem git push ``` Output: `static/dist/main.js` + `static/dist/main.css` — wird committet (kein Build-Schritt auf dem Server). **Deploy-Kette:** ``` npm run build → git push (Gitea :3000) → Bosgame: git pull → rsync → systemctl restart ``` Oder über den Self-Update-Button in Mission Control (empfohlen). **Self-Update-Button** (`POST /api/self-update`): git pull → rsync → restart — alles in einem Klick. ## Konfiguration (Env-Vars) | Variable | Default | Zweck | |---|---|---| | `MC_LLAMA_SWAP_URL` | `http://127.0.0.1:8080` | llama-swap URL | | `MC_CONFIG_PATH` | `/etc/llama-swap/config.yaml` | llama-swap Config | | `MC_MODELS_DIR` | `/srv/models` | GGUF-Ablageort | | `MC_TOKEN` | leer | Auth-Token (optional, LAN-only) | | `MC_UPDATE_CMD` | leer | Engine-Update-Befehl | | `MC_DEFAULT_TTL` | `300` | Sekunden bis Auto-Unload | | `MC_SOURCE_DIR` | `~/mission-control` | Self-Update Quelle | | `MC_MEMORY_DB` | `{MODELS_DIR}/mission-control-memory.db` | SQLite Gedächtnis | | `HERMES_SIMPLE_MODEL` | `scout` | Modell für einfache Tasks | | `HERMES_COMPLEX_MODEL` | `coder` | Modell für komplexe Tasks | | `HERMES_WINDOWS_HOST` | leer | Windows-PC IP für SSH | | `HERMES_WINDOWS_USER` | `TobisPC` | Windows SSH-Username | | `HERMES_SSH_KEY` | `~/.ssh/id_ed25519_hermes_agent` | SSH-Key für Hermes | | `PIPER_BIN` | `/opt/mission-control/piper/piper` | Piper TTS Binary | | `PIPER_VOICE` | `.../de_DE-kerstin-low.onnx` | Piper Stimm-Modell | | `WHISPER_MODEL` | `medium` | Whisper Modell-Größe | ## Konventionen - **Neuer Bereich**: `routers/.py` + `frontend/src/panels/Panel.svelte` + Nav/View in `index.html` + Import in `main.ts`. Danach `npm run build`. - **Backend SoC**: gemeinsame Logik in `config/auth/jobengine/llamaswap/hw_math`. Alles unter `/api/*`. - **Sicherheit**: Shell-Befehle → nur LAN. Secrets via stdin. Token optional. - **SQLite**: WAL-Mode aktiv, `check_same_thread=False` — ausreichend für Single-User. - **`asyncio.get_running_loop()`** statt `get_event_loop()` (Python 3.10+ kompatibel). - **Memory-Kategorien**: `user` | `instruction` | `stable` | `versioned` | `ephemeral` — Enum in `routers/memory.py`. ## Gotchas - **`${PORT}`** in llama-swap-Config → `str.replace` statt `.format` (KeyError sonst). - **`-watch-config`** bei llama-swap nötig für Auto-Einpflegen. - **`HF_HUB_DISABLE_XET=1`** bei HuggingFace-Downloads (Hänger bei ~6 MB). - **Vision-Modelle**: brauchen `--mmproj ` und `--jinja`. - **Gitea-Push** kann transient mit „Failed to authenticate" fehlschlagen → einfach nochmal. - **Piper TTS**: Binary + Stimm-Modell müssen separat installiert werden (nicht via pip). - **Whisper**: lädt beim ersten Aufruf ~1.4 GB Modell herunter (einmalig, dann gecacht). - **Hermes SSH-Key**: muss auf dem Bosgame generiert werden (`~/.ssh/id_ed25519_hermes_agent`). - **system_status-Keys**: `/api/system/status` liefert verschachtelt (`cpu.percent`, `ram.used` in Bytes) — nicht flach. `hermes_agent.py` muss entsprechend lesen. - **OpenCode Config**: Datei heißt `opencode.jsonc` (nicht `.json`), Key ist `"providers"` (Plural). - **ConnectPanel hinter NPM-Proxy**: `location.hostname` zeigt Proxy-Domain → LAN-IP Override im Verbinden-Tab setzen (localStorage). ## Projektstatus **v7 (Memory Layer)**: SQLite-Gedächtnis mit 5 Kategorien + MCP-Server für alle Tools live. **v8 (Hermes Agent)**: Chat-Agent mit Voice (Whisper STT + Piper TTS), Tool Calling, WebSocket-Streaming live. **v8.1 (Bug-Fix)**: system_status-Keys, Model-Routing, asyncio, sudo-PW für Engine-Update, Chat-History in sessionStorage. **v8.2 (UX)**: Guide-Tabs + Begriffe oben, Mobile Bottom-Nav (≤520px), Download-Links, ConnectPanel-Fixes. **v8.3 (Memory Import)**: Import aus Cloud-KIs (Claude/Gemini/ChatGPT) — zeilenweiser Batch-POST. Offene v8-Einrichtungsschritte (kein Code, nur Setup): - Piper Binary + Kerstin-Stimme installieren (Befehle im Hermes-Tab → ⚙ Setup) - Windows OpenSSH Server aktivieren + SSH-Key einrichten **Nordstern:** Den Bosgame nie wieder via SSH/Putty anfassen — 100 % Automatisierung / Klicki-Bunti.