# Konzept: Bare-Metal-Wiederaufbau + First-Run-Wizard (VOLLSTÄNDIG) > **Zweck:** Plan für den „hard crash"-Fall — die Box (`tobisniceaiarbeitstier`, Ubuntu 26.04, > AMD Ryzen AI MAX+ 395 / gfx1151, 122 GB RAM) muss von **null** wiederherstellbar sein. > **Anspruch:** *ALLES* ist erfasst — Engine, Hermes-Konfig 1:1, 3D-Avatare, Voice/Klonstimme, > Memory, Browser, MCP, Skills, Secrets. Pro Komponente entscheidet der Nutzer im Wizard: > **1:1 zurück** · **neu/Default** · **weglassen**. > > Dieses Dokument ist die **Spezifikation für eine künftige Implementierungs-Session** — es baut > noch nichts. Stand: 2026-06-28. --- ## 1. Leitprinzip: 1:1 ODER modular — der Nutzer wählt Der Wizard behandelt jede Komponente als **eigene Kachel mit drei Modi**: | Modus | Bedeutung | |---|---| | 📦 **1:1 aus Backup** | Exakter alter Zustand wird zurückgespielt (Configs, Daten, Klonstimme, Avatare). | | 🆕 **Neu / Default** | Frische Installation mit sinnvollen Defaults (z.B. entfesseltes Hermes-Profil, Default-Avatar). | | ⏭️ **Weglassen** | Komponente wird (vorerst) nicht installiert. | Ein „Alles 1:1"-Knopf wählt überall 📦 (wo ein Backup existiert), sonst 🆕. So bekommt der Nutzer entweder den exakten alten Stand oder kann gezielt entrümpeln. --- ## 2. Was es schon gibt (wiederverwenden) | Asset | Datei | Deckt ab | |---|---|---| | Code-Deploy | `deploy/deploy.sh` | git pull + venvs + Units + Restart. **Setzt Engine/llama-swap/Dirs/venvs voraus.** | | Zustands-Backup | `deploy/backup.sh` + `mc2-backup.{service,timer}` | **Aktuell** (live): mem0, `~/.hermes/{config.yaml,.env,plugins}`, llama-swap-config. Retention 14. **Für echtes 1:1 zu erweitern** — fertiges Snippet in **Anhang B** (§5). | | Restore | `deploy/restore.sh` | Spielt Tarball zurück (mit Pre-Restore-Sicherung). | | Engine | `deploy/provision-engine.sh` | llama.cpp Vulkan/RADV-Build (root). | | Voice-Setup | `voice_service/install.sh` | venv + Piper-Binary + dt. Piper-Stimmen + Chatterbox (best-effort). | | Updates | `deploy/update-engine.sh`, `update-swap.sh` | Laufende Engine/Router-Updates. | | Postchecks | `deploy/stack-postcheck.sh`, `hermes-postcheck.sh` | Funktionsprüfung → Wizard-Verifikationsschritt. | --- ## 3. VOLLSTÄNDIGER Komponenten-Katalog > **Scan-verifiziert (2026-06-28)** gegen `backend/config.py`, alle `backend/services/*` & `routers/*`, > `frontend/src/{nav.ts,views,components/voice}`, `voice_service/app.py`, `mem0_service/`, `deploy/*`. > Alle persistenten Schreibpfade, Dienste, Secrets und Env-Vars sind unten erfasst. Legende Restore-Quelle: 📦 = aus Backup-Tarball · ⬇️ = Re-Download/Install (Skript) · 🌐 = Git · 🔑 = Secret (Nutzer/Generieren) · 🆕 = im Wizard neu gewählt. „Im Backup?" = deckt der **aktuelle** `backup.sh` es ab. ### A · OS & System (L0, root/sudo, einmalig) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | Ubuntu 26.04, User `hitonabi`, `enable-linger` | — | ⬇️ manuell | n/a | | System-Pakete: python3.14+venv, git, curl, jq, ttyd, uv | — | ⬇️ apt/curl | nein | | Vulkan-Stack: mesa-vulkan-drivers, libvulkan1, vulkan-tools | — | ⬇️ apt | nein | | Chrome-Libs (Browser): `agent-browser install --with-deps` | — | ⬇️ apt | nein | | Verzeichnis-Layout: `/srv/models/{,mem0,mc2-backups,drafts}`, `/etc/llama-swap/` | — | ⬇️ mkdir+chown | nein | ### B · Inferenz-Engine + Router (L1, root) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | llama.cpp (Vulkan) → `llama-server` | `/opt/llamacpp-vulkan`, `/usr/local/bin/llama-server` | ⬇️ provision-engine.sh / update-engine.sh (ggml-org Release) | nein (re-build) | | **llama-swap** Binary (Router `:8080`) | `/usr/local/bin/llama-swap` | ⬇️ **bekannt:** `mostlygeek/llama-swap`-Release (Rezept in `update-swap.sh`) | nein (re-download) | | **llama-swap systemd-System-Unit** | `/etc/systemd/system/llama-swap.service` (+ `.d/` Drop-ins) | ⬇️ Bootstrap legt sie an — **kompletter Unit-Inhalt in Anhang A** (von der Box abgegriffen; Drop-ins via provision-engine.sh) | nein | | llama-swap-Config (Modelle/Rollen) | `/etc/llama-swap/config.yaml` | 📦 | **ja** | | Draft-Modelle (Spec-Decoding) | `/srv/models/drafts/` | ⬇️ Re-Download | nein | ### C · MC2-App (L2, userspace) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | MC2-Code | `~/mission-control-v2` | 🌐 Git (Gitea) | n/a | | Backend-venv (Python 3.14) | `backend/.venv` | ⬇️ deploy.sh | nein (rebuild) | | Frontend (gebaut, inkl. **3D-Avatar `avatar.vrm`**) | `frontend/dist`, `frontend/public/avatar.vrm` | 🌐 Git | n/a | | systemd-User-Dienst `mission-control-2` (`:9001`) | `~/.config/systemd/user/` | ⬇️ deploy.sh | nein | ### D · 3D-Avatar (Sprechen-Tab) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | Default-Avatar (VRM) | `frontend/public/avatar.vrm` (→ dist) | 🌐 Git | n/a | | Renderer | `frontend/src/components/voice/Avatar3D.tsx` | 🌐 Git | n/a | | **Eigene/zusätzliche Avatare** (falls Nutzer welche ablegt) | **TODO: Ablageort definieren** (z.B. `/srv/models/avatars/` + DB-Verweis) | 📦/🆕 | **nein (Lücke)** | > Heute ist der Avatar **fest** (`avatar.vrm`, kommt mit dem Git-Frontend zurück). Wenn künftig > Nutzer-Avatare hochgeladen werden, brauchen sie einen persistenten Ablageort, der ins Backup geht. ### E · Voice-Sidecar (STT + TTS + Klonstimme) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | Voice-venv (Python 3.12) | `~/.voice/venv` | ⬇️ install.sh | nein (rebuild) | | STT (faster-whisper Modell) | `~/.voice/` (Cache) | ⬇️ install.sh / 1. Start | nein | | Piper-Binary + dt. Stimmen (thorsten/kerstin) | `~/.voice/piper`, `~/.voice/voices` | ⬇️ install.sh | nein | | Chatterbox (Premium-TTS, CPU-torch) | venv | ⬇️ install.sh (best-effort) | nein | | **Klonstimme / Voice-Referenz-Audio** (Nutzer) | `~/.voice/refs/ref.wav` (`VOICE_REFS_DIR`, `/api/voice/reference`) | 📦 | **nein → Anhang B** | | ElevenLabs-Key | `~/.hermes/.env` | 🔑 | ja | | Stimm-/Lautstärke-Wahl | Browser-`localStorage` (pro Gerät) | 🆕 client | n/a | | Dienst `voice-service` (`:8650`) | systemd-User | ⬇️ deploy.sh | nein | ### F · Mem0 (Langzeitgedächtnis) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | Mem0-venv (Python 3.12, uv) | `~/.mem0/venv` | ⬇️ deploy.sh | nein (rebuild) | | **Gedächtnis-Daten (Chroma + history.db)** | `/srv/models/mem0/` | 📦 | **ja** | | Hermes-Memory-Plugin | `~/.hermes/plugins/mc2-memory/` | 📦/🌐 | ja | | Dienst `mem0-service` (`:8765`) | systemd-User | ⬇️ deploy.sh | nein | ### G · Hermes-Agent (das Herz) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | Hermes-Code | `~/.hermes/hermes-agent` | 🌐 Git (NousResearch) | nein (re-clone) | | Bundled Node v22 | `~/.hermes/node/bin` | ⬇️ (kommt mit Hermes) | nein | | Hermes-venv | `~/.hermes/hermes-agent/venv` | ⬇️ rebuild | nein | | **`config.yaml` 1:1** (Toolsets, MCP, Engine, Browser, Personalities, alles) | `~/.hermes/config.yaml` | 📦 | **ja** | | **`.env` (Secrets: TELEGRAM_BOT_TOKEN, API_SERVER_KEY, ElevenLabs …)** | `~/.hermes/.env` | 📦/🔑 | **ja** | | Plugins | `~/.hermes/plugins/` | 📦 | ja | | **Skills (eigene)** | `~/.hermes/skills/` (45M; `.hub`-Cache re-downloadbar) | 📦 | **nein → Anhang B (ohne .hub)** | | Sessions/History (optional) | `~/.hermes/sessions/` (856K) | 📦 | **nein → Anhang B** | | Checkpoints (optional) | `~/.hermes/checkpoints/` (existiert nicht) | ⏭️ skip | nein | | **Token-/Ersparnis-Statistik** | `~/.hermes/token_stats.json` | 📦 | **nein → Anhang B** | | Dienst `hermes-gateway` (`:8642`) | systemd-User | ⬇️ | nein | | Hermes-Terminal (ttyd → `hermes chat`, `:7681`) | systemd-User `hermes-terminal` | ⬇️ deploy.sh (+ttyd apt) | nein | ### H · MCP-Server (4) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | `mission-control-memory`, `-stack` (MC2-venv) | `~/mission-control-v2/mcp/*.py` | 🌐 Git | über config.yaml | | `hermes-pc-control`, `hermes-web-fetch` (Hermes-venv) | dito | 🌐 Git | über config.yaml | | MCP-Verdrahtung | `~/.hermes/config.yaml → mcp_servers` | 📦 | ja | ### I · Browser-Stack | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | agent-browser (npm global) | `~/.local/...`, symlink `~/.hermes/node/bin` | ⬇️ npm i -g | nein | | Chrome (engine) + System-Libs | `~/.agent-browser/browsers/` + apt-Libs | ⬇️ install --with-deps | nein | | lightpanda (optional, leicht) | `~/.local/bin/lightpanda` | ⬇️ Download | nein | | Browser-Verdrahtung (engine=chrome, toolset) | `~/.hermes/config.yaml` | 📦 | ja | ### J · Modelle (GGUF — der große Brocken) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | GGUF-Modelle (Brain, fast, heavy, coder, vision, embedding …) | `/srv/models/` | ⬇️ Re-Download aus llama-swap-Manifest | **nein (zu groß, bewusst)** | ### K · Extern (anderer Rechner) | Komponente | Ort | Quelle | Im Backup? | |---|---|---|---| | PC-Executor (Windows) | `client/hermes-pc/` → Scheduled Task | 🌐 Git + Task | n/a (anderer Host) | | Hermes-WebUI (nesquena, optional, `:8787`) | `~/hermes-webui` | ⬇️ git clone | nein | --- ## 4. Ziel-Architektur ### 4.1 `deploy/bootstrap.sh` — orchestrierter From-Zero-Lauf - **Idempotent & resumierbar** (Schritt-Marker in `~/.mc2-bootstrap.state`). - **Getrennt nach sudo-Bedarf**: `bootstrap-root.sh` (L0+L1, bewusst mit sudo) + `bootstrap.sh` (L2+, sudo-frei = Kern ist `deploy.sh`). Passt zum Nordstern „Runtime ohne sudo". - **Mündet in den Wizard**: startet MC2 im First-Run-Modus, gibt Wizard-URL aus. Phasen: `0 Vorflug → 1[sudo] System+Dirs → 2[sudo] Engine+llama-swap → 3 Code(MC2+Hermes+Node) → 4 venvs(backend/mem0/voice/hermes) → 5 Browser → 6 deploy.sh(Units/enable/restart) → 7 Restore(optional) → 8 Wizard hoch + postcheck`. ### 4.2 First-Run-Wizard (browserbasiert, von MC2 serviert) MC2 erkennt unkonfigurierten Zustand → Frontend-Route `/setup` statt Dashboard. Schritte: 1. **Systemcheck** — Live-Ampel je Komponente aus §3 (`GET /api/setup/status` + `…/system/services`). 2. **Restore-Quelle wählen** — Backup-Tarball erkennen → globaler Modus „Alles 1:1" / „selektiv" / „frisch". 3. **Komponenten-Auswahl (Kernstück)** — pro Katalog-Eintrag aus §3 eine Kachel mit 📦/🆕/⏭️ (siehe §1). Zeigt Größe + ob Backup-Daten vorhanden. 4. **Netzwerk & Identität** — Box-IP (→ `HERMES_TERMINAL_URL`, `PC_EXECUTOR_URL`), Hostname. 5. **Secrets** 🔑 — `TELEGRAM_BOT_TOKEN`, erlaubte User-ID, `API_SERVER_KEY` (oder generieren), ElevenLabs-Key → `~/.hermes/.env` (chmod 600). Bei 📦 vorbefüllt aus Backup. 6. **Hermes-Profil** — Brain-Alias + Toolset-Profil (Default = entfesselt: vision/tts/memory/browser an, image_gen/video aus — siehe [[project-hermes-setup]]). Bei 📦 = exakte alte `config.yaml`. 7. **Avatar & Voice** — Avatar wählen (Default-VRM oder eigener), Stimme/Klonstimme (📦 Referenz-Audio zurück, oder neu aufnehmen/hochladen). 8. **Modelle** — aus llama-swap-Manifest automatisch nachladen (`POST /api/models/install`, Fortschritt `GET /api/jobs`) ODER geführte Discover-Neuauswahl. Reihenfolge: Brain → heavy → Rest. 9. **Externe Checkliste** — PC-Executor (Windows-Task), Hermes-WebUI als Haken. 10. **Verifikation & Abschluss** — `stack-postcheck.sh` + `hermes-postcheck.sh` → grün/rot-Liste → Dashboard. **Technik:** neuer Router `backend/routers/setup.py` (`GET /api/setup/status`, `POST /api/setup/{secrets,network,hermes,components,finish}`). First-Run-Gate: MC2 prüft beim Boot Marker `~/.mc2-setup-done` bzw. Pflicht-Secrets → leitet auf `/setup`. --- ## 5. Backup-Scope für echtes 1:1 ERWEITERN (umzusetzen — Snippet in Anhang B) Der **aktuelle** `backup.sh` (live auf der Box, unverändert) reicht für „1:1" nicht. Für die Bau-Session liegt das **fertige Erweiterungs-Snippet in Anhang B** — es ergänzt den Tarball um: - **Voice-Klonstimme** → `~/.voice/refs/` (`ref.wav`) - **Token-/Ersparnis-Statistik** → `~/.hermes/token_stats.json` - **Hermes-Skills** → `~/.hermes/skills/` (re-downloadbarer `.hub`-Cache per `tar --exclude` ausgelassen) - **Hermes-Sessions/History** → `~/.hermes/sessions/` Restore soll skills/sessions **mergen** (frisch geladenen `.hub` nicht überschreiben) und `voice-service` mit neu starten. **Offen bleibt:** eigene Avatare (sobald Upload existiert — Ablageort heute undefiniert, siehe §3·D). **Bewusst NICHT im Backup (re-downloadbar/rebuildbar):** Piper-Stimmen (install.sh), `.hub`-Skill-Cache, `/srv/models/mc2-discover.json` (Cache), `/srv/models/mc2-memory.db` (Legacy-Migration), alle venvs, GGUF-Modelle. → Aufgabe der Bau-Session: `backup.sh` + `restore.sh` um diese Pfade erweitern (mit klarer „opt-in für große/optionale Teile"-Logik), und den MANIFEST-Inhalt entsprechend. --- ## 6. Secrets-Strategie - Single Source: `~/.hermes/.env` (chmod 600), im Tarball (selbst 600). - Rebuild ohne Backup → Wizard-Schritt 5 erzeugt sie. `API_SERVER_KEY` generierbar; Telegram/ElevenLabs liefert Nutzer. - Nie ins Git, nie in Logs, nie in die MC2-DB. **Off-Box-Spiegelung des Tarballs noch offen** ([[mc2-backup-restore]]). ## 7. Modell-Strategie - **A (empfohlen):** `/etc/llama-swap/config.yaml` (im Backup) listet alle Modelle → Wizard leitet Repos/Quants ab und lädt automatisch (`/api/models/install`). „Ein Klick, lädt über Nacht." - **B:** geführte Discover-Neuauswahl je Rolle. Reihenfolge Brain → heavy → Rest, danach `warmup.sh`. --- ## 8. Implementierungs-Reihenfolge (neue Session) 1. ✅ **Box-Verifikation erledigt (2026-06-28, nur gelesen — nichts verändert):** llama-swap.service-Inhalt in **Anhang A**; skills/sessions/refs/token_stats existieren (Pfade in §3 verifiziert); Backup-Erweiterung als fertiges Snippet in **Anhang B**. **Keine offenen Box-Fragen mehr** außer §10·3–6. → mit Schritt 2 starten. 2. `backup.sh`/`restore.sh` um die 1:1-Lücken erweitern (§5). 3. `deploy/bootstrap.sh` + `bootstrap-root.sh` (Phasen, State-Marker); llama-swap-Install skripten. 4. `backend/routers/setup.py` + First-Run-Gate. 5. Frontend `/setup`-Wizard (Schritte 1–10), Komponenten-Auswahl als Kernstück; bestehende Views (Cockpit/AgentView/Sprechen) wiederverwenden. 6. Modell-Restore-aus-Manifest. 7. **Abnahme in frischer VM** (§9). Vorschlag: 2–4 zuerst (Skelett lauffähig), Wizard danach. Branch + PR. ## 9. Abnahmekriterien - Frisches Ubuntu 26.04 → `bootstrap-root.sh` + `bootstrap.sh` → laufender Stack, kein Spezialwissen. - Postchecks grün; Telegram, Voice (inkl. Klonstimme bei 📦), 3D-Avatar, Browser funktionieren. - „Alles 1:1" stellt mem0, Hermes-config.yaml, Secrets, Klonstimme, Skills exakt wieder her. - Selektiver Modus: einzelne Komponenten ⏭️ überspringbar, Stack läuft trotzdem. - Idempotenz: zweiter Lauf = No-op. ## 10. Offene Entscheidungen (vor dem Bau) 1. ~~llama-swap systemd-Unit-Inhalt~~ → **geklärt: kompletter Unit in Anhang A** (in der Bau-Session anlegen). 2. ~~Voice-Referenz-Audio-Ort~~ → **geklärt: `~/.voice/refs/`** (Backup-Snippet in Anhang B, in der Bau-Session umsetzen). 3. **Eigene Avatare**: künftiger Upload-/Ablage-Mechanismus + Backup-Pfad (einziger offener 1:1-Daten-Punkt). 4. **Off-Box-Backup-Ziel** (NAS/2. Platte/Cloud) — [[mc2-backup-restore]]. 5. **Python 3.14** auf frischem Ubuntu beschaffen (deadsnakes?). 6. **Bootstrap-sudo-Modell**: getrenntes `bootstrap-root.sh` (empfohlen) vs. interaktives sudo. ## 11. Referenzen - `backend/config.py`, [[project-mc2-architecture]], [[project-stack-state]] - [[project-hermes-setup]], `docs/HERMES_SETUP.md` (entfesseltes Profil, Browser, PC-Executor) - [[voice-sprechen-feature]] (Voice + 3D-Avatar), [[mem0-memory-architecture]], [[mc2-backup-restore]] - `deploy/{deploy,backup,restore,provision-engine,stack-postcheck,warmup}.sh`, `voice_service/install.sh` --- ## Anhang A — `llama-swap.service` (1:1 von der Box abgegriffen, 2026-06-28) Base-Unit nach `/etc/systemd/system/llama-swap.service` (root). User/GFX sind boxspezifisch (hitonabi, gfx1151 → HSA 11.5.1) — auf anderer Hardware anpassen. Die `.d/`-Drop-ins (`vulkan.conf`, `warmup.conf`) legt `provision-engine.sh` an. ```ini [Unit] Description=llama-swap (lokaler LLM Router) After=network-online.target Wants=network-online.target [Service] Type=simple User=hitonabi Environment=HSA_OVERRIDE_GFX_VERSION=11.5.1 Environment=PATH=/usr/local/bin:/usr/bin:/bin ExecStart=/usr/local/bin/llama-swap --config /etc/llama-swap/config.yaml --listen 0.0.0.0:8080 --watch-config Restart=on-failure RestartSec=3 [Install] WantedBy=multi-user.target ``` ```ini # /etc/systemd/system/llama-swap.service.d/vulkan.conf [Service] Environment=LD_LIBRARY_PATH=/opt/llamacpp-vulkan ``` ```ini # /etc/systemd/system/llama-swap.service.d/warmup.conf [Service] ExecStartPost=-/usr/local/bin/llama-swap-warmup.sh ``` **Erstinstall-Reihenfolge:** `bash deploy/update-swap.sh` (Binary) → Unit kopieren → `sudo bash deploy/provision-engine.sh` (Engine+Drop-ins) → `sudo systemctl enable --now llama-swap`. --- ## Anhang B — Backup-Scope-Erweiterung für echtes 1:1 (fertiges Snippet) In `deploy/backup.sh` ergänzen (Variablen oben: `VOICE="${VOICE_HOME:-$HOME/.voice}"`, Stage zusätzlich `"$STAGE/voice"`): ```bash # 1:1-Erweiterung (scan-verifiziert 2026-06-28): [ -f "$HERMES/token_stats.json" ] && cp -a "$HERMES/token_stats.json" "$STAGE/hermes/" || true [ -d "$HERMES/skills" ] && cp -a "$HERMES/skills" "$STAGE/hermes/skills" || true [ -d "$HERMES/sessions" ] && cp -a "$HERMES/sessions" "$STAGE/hermes/sessions" || true [ -d "$VOICE/refs" ] && cp -a "$VOICE/refs" "$STAGE/voice/refs" || true ``` tar-Aufruf um den re-downloadbaren Skill-Cache erleichtern: ```bash tar --exclude='./hermes/skills/.hub' -czf "$OUT" -C "$STAGE" . ``` In `deploy/restore.sh` spiegelbildlich (skills/sessions **mergen**, nicht ersetzen) und `voice-service` mit neustarten: ```bash VOICE="${VOICE_HOME:-$HOME/.voice}" SERVICES="mem0-service voice-service mission-control-2 hermes-gateway" [ -f "$STAGE/hermes/token_stats.json" ] && cp -a "$STAGE/hermes/token_stats.json" "$HERMES/" [ -d "$STAGE/hermes/skills" ] && { mkdir -p "$HERMES/skills"; cp -a "$STAGE/hermes/skills/." "$HERMES/skills/"; } [ -d "$STAGE/hermes/sessions" ] && { mkdir -p "$HERMES/sessions"; cp -a "$STAGE/hermes/sessions/." "$HERMES/sessions/"; } [ -d "$STAGE/voice/refs" ] && { mkdir -p "$VOICE/refs"; cp -a "$STAGE/voice/refs/." "$VOICE/refs/"; } ```