This repository has been archived on 2026-07-22. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mission-control/CLAUDE.md
T
Hitonabi af0e63c9d6 docs(v9): Phase 5 (Dashboard-Adoption) + Phasen 6-8 in ROADMAP
Kurswechsel dokumentiert: eingebettetes Hermes-Web-Dashboard statt Eigenbau-Chat.
CLAUDE.md: hermes_ui-Router, HERMES_DASHBOARD_URL, Dashboard-Gotcha, Projektstatus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 16:51:52 +02:00

140 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
- **`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-WS **proxyt zum Hermes-Agent-Server (:8642)** + transcribe(Whisper)/tts(Piper)/status/pubkey + **Cockpit-Reads** agent/cron/skills (Phase 4)
- `hermes_ui.py`**Reverse-Proxy** auf das eingebettete Hermes-Web-Dashboard (`/hermes-ui/`, HTTP + WS-Bridge `pty/ws/pub/events`, `X-Forwarded-Prefix`). Der Chat lebt jetzt hier (iframe), nicht mehr im Eigenbau.
- **`hermes_control.py`** — read-only Control-Plane: liest Agent-Status (`gateway_state.json` + Cron-Heartbeat), Cron-Jobs & Skills via `hermes`-CLI (`COLUMNS=400`, Rich-Tabelle geparst). TTL-Cache.
**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**: aktuell Eigenbau als Teil von Mission Control; **ab v9 das Nous Hermes-Agent-Framework** als eigener Dienst (`hermes-agent.service`, OpenAI-API auf `:8642`, base_url → llama-swap, MCP-Client bindet `mcp_memory.py` ein). Voice (Whisper STT + Piper TTS) bleibt in Mission Control und wrappt :8642.
## 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_API_URL` | `http://127.0.0.1:8642/v1` | Hermes-Agent-Server (OpenAI-API) |
| `HERMES_API_KEY` | aus `~/.hermes/.env` | API-Key des Hermes-Servers (sonst Env) |
| `HERMES_HOME` | `~/.hermes` | Hermes-Agent State-Dir (Cockpit-Reads) |
| `HERMES_BIN` | `~/.local/bin/hermes` | Hermes-CLI (Cron/Skills-Reads) |
| `HERMES_DASHBOARD_URL` | `http://127.0.0.1:9119` | Hermes-Web-Dashboard (eingebettet via `/hermes-ui/`) |
| `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/<bereich>.py` + `frontend/src/panels/<Bereich>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 <projektor>` 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. Konsumenten müssen entsprechend lesen.
- **Hermes-Server-Key**: `routers/hermes.py` proxyt zu `:8642` und liest den Key bei Bedarf aus `~/.hermes/.env` (`API_SERVER_KEY`) — MC muss als User `hitonabi` laufen, sonst kein Lesezugriff.
- **Hermes-Dashboard (Phase 5)**: braucht Extras `uv pip install --python ~/.hermes/hermes-agent/venv/bin/python -e ".[web,pty]"` und einen einmaligen UI-Build (erster `hermes dashboard`-Start ohne `--skip-build`; Output → `hermes_cli/web_dist`). Dienst: `~/.config/systemd/user/hermes-dashboard.service` (an `127.0.0.1:9119` gebunden, `--skip-build`). Wird unter `/hermes-ui/` per `X-Forwarded-Prefix` geproxyt — nie ohne diesen Header proxen, sonst absolute Asset-Pfade kaputt. `/hermes-ui/*` ist bewusst **ohne** MC-Token (LAN-only; Dashboard self-auth auf Loopback).
- **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.
**v9 (Hermes-Agent-Adoption, Entscheidung 2026-06-23)**: Eigenbau-Agent → Nous Hermes-Agent-Framework (MIT). MC wird Control-Plane. Eigenes Memory bleibt via MCP erhalten. Phasen 03 live (harter Cutover: `hermes_agent.py` entfernt) **+ Phase 4**: Agent-**Cockpit** (Status/Cron/Skills) via `hermes_control.py` **+ Phase 5 (Kurswechsel)**: Eigenbau-Chat ersetzt durch das **eingebettete Hermes-Web-Dashboard** (`hermes-dashboard`-Dienst :9119, MC-Reverse-Proxy `/hermes-ui/`, iframe). Offen: Phase 6 (volle lokale Rechte), Phase 7 (Agent-Modell Hermes 4 14B), Phase 8 (insights/Memory im Cockpit), Self-Update für `hermes-gateway`+`hermes-dashboard`. Siehe ROADMAP v9.
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.