From c28aa4a6a2bc7276279728ef6259d1e1c6cdf916 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Sat, 25 Jul 2026 22:04:44 +0200 Subject: [PATCH] README aktualisiert + Kritiker auf 16k gedeckelt (Prefill-Befund) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README war auf dem Stand "Final-Version eingefroren" und kannte weder Governor, Coding-Bahn, CI-Ampel noch den Weg einer Idee. Neu geschrieben mit den echten Ports/Diensten, den gemessenen Modell-Rollen und den vier Qualitaets-Toren. Alle Verweise gegen den Baum geprueft. Dabei aufgefallen: das eigene VERDIKT vom 24.07. ("Devstral bricht beim 32K-Prefill auf 63 t/s ein") widerlegt meine Begruendung "ein Kritiker liest viel und schreibt wenig, also stoert die Langsamkeit nicht" — es ist genau das LESEN, das einbricht. Nachgemessen: Prefill 265-318 t/s (Coder 754). Der Kritiker ist deshalb in llama-swap UND in beiden opencode.json auf 16384 gedeckelt; schlimmster Fall je Review jetzt unter einer Minute statt 8+ Minuten. VERDIKTE um zwei Eintraege ergaenzt: die enge Kritiker-Rolle mit Deckel, und die llama-swap-Gruppenregel (eine Gruppe resident, persistent:false, OOM-Grenze). Co-Authored-By: Claude Opus 5 --- README.md | 178 +++++++++++++++++++++--------- deploy/opencode/opencode.box.json | 37 +++++-- deploy/opencode/opencode.pc.json | 37 +++++-- docs/wissen/VERDIKTE.md | 16 +++ 4 files changed, 202 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 5d23062..d70d120 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,150 @@ # Mission Control 2.0 -Komponierbarer Local-AI-Stack für den Bosgame M5 (Strix Halo). Läuft **live auf der Box** -als sudo-freier systemd-User-Dienst (`:9001`) und ist als **Final-Version eingefroren** — -Pflege übernehmen ab jetzt die selbst-wartenden Box-KIs (Auto-Update mit Fangnetz + die -„Werkstatt"), nicht mehr manuelle Releases. +Steuerzentrale des lokalen KI-Stacks auf dem **Bosgame M5** (AMD Ryzen AI MAX+ 395 „Strix Halo", +122 GB Unified Memory, **keine dedizierte GPU** — llama.cpp über **Vulkan/RADV**). Läuft live als +sudo-freier systemd-User-Dienst und ist auf **Autonomie** ausgelegt: Die Box wartet sich selbst, +prüft sich selbst und meldet sich, wenn etwas nicht stimmt. -**Schichten:** Engine (llama.cpp **Vulkan/RADV** auf Strix Halo) · Router (**llama-swap**, -Ko-Residenz-Warm-Set) · **Builtin-Routing-Gateway** in MC2 (`model: auto`, kein externer -LiteLLM — scheitert auf Python 3.14) · Mission Control 2.0 (FastAPI + React/shadcn) · -**Hermes Agent** (api_server-Gateway :8642, Tools/MCP/Telegram/cron) · auto-lernendes -**Gedächtnis** (Mem0-Sidecar, semantisch). Jede Schicht hinter stabilem Vertrag austauschbar. +> **100 % lokal.** Kein Cloud-Modell, kein externer Dienst im Datenpfad. -> **Sprachassistentin Lucy** (Voice + 3D-Avatar) ist in ein **eigenes Repo** ausgelagert -> (`Hitonabi/lucy`) und spricht über den Hermes-Gateway. Aus MC2 selbst sind die Voice-/ -> Web-Reste entfernt — MC2 ist die Steuerzentrale, kein Sprach-Frontend. +## Die drei Bahnen -## Status: **live + eingefroren (MC2 Final)** +| Bahn | Was sie tut | Wo | +|---|---|---| +| **Steuerzentrale** | Modelle, Routing, Wartung, Gedächtnis, Ideen-Queue, Auftragsbuch | MC2 `:9001` | +| **Coding** | Zed + OpenCode am Tag, `opencode-lauf.sh` in der Nacht — **ein Regelwerk, zwei Auslöser** | Governor `:8100` | +| **Lucy** | Sprach-Companion mit 3D-Avatar, Augen und Ohren | eigenes Repo `Hitonabi/lucy` | -Der ganze Stack ist auf der Box in Betrieb und auf **Autonomie** ausgelegt (Ziel: läuft auch -ohne Betreuung monatelang weiter): +Lucy holt ihr Hirn über MC2, spricht aber nie durch den Governor — ein Gespräch ist keine +Bau-Sitzung und wird nie unterbrochen. -- **Modelle & Routing** — Discover (live HF + Fit/Caps), Engine-Write (register, `groups`/ - Ko-Residenz, vocab-geprüfte Spec-Drafts), Gateway `model: auto` + Fallbacks. -- **System & Wartung** — Status (CPU/RAM/GPU/Disk), **ehrliche Speicher-Zahlen** (echte KV-Bytes - aus GGUF-Architektur), Logs mit Fehler-Filter, Dienst-Neustart (sudo-frei). -- **Updates mit Fangnetz** — OS/Engine/Router/Hermes per Timer: Backup → Update → Postcheck → - bei Fehler **Auto-Rollback + Pin**; verständliche Zusammenfassung („Musst du etwas tun?") in - Lucys Stimme. Eigene Software wird eingefroren, nicht geupdatet. -- **Gedächtnis** — Mem0-Sidecar (auto-lernend, semantisch), 4 Kategorien, Auto-Dedupe. -- **Selbsterhaltung** — Health-Wächter (`sentry`), Warm-Set-Wächter (`warmer`), tägliche - Self-Smokes, Lucy-Watchdog + Alarmkette; **Werkstatt** (Hermes wartet den Stack via Gitea- - Branch → Gate → Deploy selbst). +## Ports & Dienste -API: `health · models · discover · fit · models/register · groups · routing · system/* · -maintenance/* · connect · memory/* · agent/* · voice/announce · reminders/*`. MCP: `mcp/`. -Box-Runbooks: [`docs/HERMES_SETUP.md`](docs/HERMES_SETUP.md), [`docs/RUNBOOK.md`](docs/RUNBOOK.md), -[`docs/BEDIENUNG.md`](docs/BEDIENUNG.md) + `deploy/` (Units, `deploy.sh`, `backup.sh`, `warmup.sh`). +| Port | Dienst | Erreichbar | +|---|---|---| +| `9001` | **MC2** (FastAPI + React) — Cockpit, API, Konsole | LAN | +| `8100` | **Governor** — Token-Wächter vor dem Gateway | LAN | +| `8080` | **llama-swap** — Modell-Router | LAN | +| `9010` | `mc2-gateway` — `/v1`-Datenpfad (`model: auto`, Bild-Weiche) | loopback | +| `8642` · `9119` | Hermes-Gateway · Hermes-Web-UI | loopback | +| `8765` · `8650` | Mem0-Sidecar · Voice-Sidecar (STT/TTS) | loopback | +| `7682` | ttyd — Box-Konsole, same-origin unter `/console/` | loopback | + +Units in [`deploy/`](deploy/): `mission-control-2` · `mc2-gateway` · `mc2-steward` · `governor` · +`mem0-service` · `voice-service` · `box-console` · `hermes-builtin-ui` + Timer für Backup, +Auto-Update, Self-Smoke und Bagatell-Annahme. `llama-swap` läuft als System-Unit. + +## Der Weg einer Idee + +``` +Idee in MC2 → Gitea-Repo (mit CI-Ampel + VERIFY) → in Zed bauen → Ampel → main + └── oder nachts: Hermes-Cron → opencode-lauf.sh → dieselben Regeln +``` + +Jedes neue Repo wird von [`deploy/gitea-repo-create.sh`](deploy/gitea-repo-create.sh) **mit beiden +Wächtern geboren**: + +- **`.gitea/workflows/ci.yml`** — die Außen-Prüfung nach dem Push (Gitea Actions) +- **`VERIFY`** — die Innen-Prüfung: eine Zeile, wie man das Projekt testet. Das OpenCode-Plugin + führt sie nach jeder Etappe aus und gibt rote Tests dem Agenten **sofort** zurück, statt sie + erst der CI zu zeigen. Keine `VERIFY`-Datei = Prüf-Tor aus. + +## Modelle & Rollen + +Gemessen auf der Box (25.07.2026, Vulkan, Q4): + +| Rolle | Modell | Tempo | Aufgabe | +|---|---|---|---| +| `coder` | Qwen3-Coder-Next (80B-A3B) | **51,5 t/s** · Prefill **754 t/s** | Plant und baut — Kopf der Coding-Mannschaft | +| `hermes` / `fast` | Qwen3.6-35B-A3B | **69,6 t/s** | Lucys Hirn **und** der Sucher-Subagent. Immer warm | +| `kritiker` | Devstral-Small-2-24B | **15,0 t/s** · Prefill **265–318 t/s** | Liest gegen — bewusst **fremde Modellfamilie** (Mistral statt Qwen) | +| `vision` | Qwen3-VL-30B-A3B | auf Abruf | Lucys Augen | +| `heavy` | gpt-oss-120b | nur nachts | Chef-Gutachter (4:30). **Nie tagsüber** — verdrängt das warme Set | +| `embed` · `reranker` | Qwen3 0.6B | immer warm | Gedächtnis + Feinsortierung | + +‼️ **Der Kritiker ist bewusst auf 16k Kontext gedeckelt.** Devstral ist ein *dichtes* Modell — +auf dieser bandbreitenbegrenzten Box bricht sein Prefill mit wachsendem Kontext ein (bei 32k +gemessene 63 t/s ≈ **9 Minuten nur zum Lesen**). Mit dem 16k-Deckel bleibt der schlimmste Fall +je Review unter einer Minute. Deshalb ist er der **Gegenleser für Etappen**, nicht der Coder — +als Coder ist er auf dieser Box disqualifiziert (siehe VERDIKTE). + +‼️ **Speicher-Regel:** `Warm-Set + größtes On-Demand-Modell ≤ ~115 GB`. Die ko-residente Gruppe +(`groups.brains` in der llama-swap-Config) muss **`persistent: false`** sein — sonst räumt +llama-swap vor einem großen Modell nicht ab und der Kernel schießt Prozesse ab. Details und +Messwerte: [`docs/wissen/VERDIKTE.md`](docs/wissen/VERDIKTE.md). + +## Qualitäts-Tore + +1. **Werkzeug-Zaun** ([`deploy/opencode/plugin/`](deploy/opencode/plugin/)) — blockt `git push`, + `rm -rf`, `sudo`, `curl | sh` und Fremd-Hosts im Agentenlauf. +2. **Prüf-Tor** — `VERIFY` nach jeder Etappe; rot → der Agent repariert selbst weiter (max. 3 Runden). +3. **Governor** ([`deploy/governor/`](deploy/governor/)) — zählt Tokens ehrlich (aus den echten + `usage.prompt_tokens` jeder Antwort, selbstkalibrierend). Bei ~45.000: Savepoint schreiben und + Sitzung sauber beenden. Bei ~50.000: harter Riegel. Sichtbar als Kachel im Cockpit. +4. **CI-Ampel** — Lint (ruff) · Import/Syntax (compileall) · Frontend-Build. Läuft bei jedem Push. + +Gemeinsame Lehre dahinter: **Wissen lebt in Datei + git, nicht im schrumpfenden Chat-Kontext.** +Kontext-Komprimierung löscht still die Regeln mit. + +## Selbsterhaltung + +- **Health-Wächter** (`sentry`) + **Warm-Set-Wächter** (`warmer`, per Env abschaltbar) +- **Updates mit Fangnetz** — Backup → Update → Postcheck → bei Fehler **Auto-Rollback + Pin** +- **Melde-Briefkasten** (`/api/voice/announce`) — alles, was die Box von sich aus sagen will; + Lucy pollt ihn und spricht es. Absender `loop` = Coding-Ereignisse +- **Gedächtnis** — Mem0-Sidecar, auto-lernend, semantisch, mit Auto-Dedupe +- Tägliche Self-Smokes, Zeitmaschine (Snapshot + Ein-Klick-Restore), Chronik der autonomen Taten + +## API (Auswahl) + +`health · models/* · discover · fit · groups · routing/* · system/* · maintenance/* · connect · +memory/* · agent/* · **governor** · ideen/* · auftragsbuch/* · chronik · eigenleben · wissen · +zeitmaschine/* · reminders/* · voice/* · events (SSE)` +OpenAI-kompatibel: `/v1/chat/completions`, `/v1/completions`. MCP-Server: [`mcp/`](mcp/). ## Entwickeln -**Backend:** ```bash +# Backend cd backend python -m venv .venv && .venv/Scripts/python -m pip install -r requirements.txt # Windows .venv/Scripts/python -m uvicorn app:app --port 9000 + +# Frontend (Dev, proxyt /api → :9000) +cd frontend && npm install && npm run dev # http://localhost:5173 + +# Frontend (Build → wird vom Backend ausgeliefert) +cd frontend && npm run build # → frontend/dist ``` -**Frontend (Dev, proxyt /api → :9000):** -```bash -cd frontend -npm install -npm run dev # http://localhost:5173 -``` - -**Frontend (Build → wird vom Backend ausgeliefert):** -```bash -cd frontend && npm run build # → frontend/dist -``` +`frontend/dist` **wird mitcommittet** — die Box hat kein Node; Deploy ist ein `git pull` plus +Dienst-Neustart. Vor jedem Commit lohnt der Ampel-Vorlauf: `ruff check .` und `npm run build`. ## Env-Vars (Auswahl) | Variable | Default | Zweck | |---|---|---| -| `MC_LLAMA_SWAP_URL` | `http://127.0.0.1:8080` | Engine | -| `MC_CONFIG_PATH` | `/etc/llama-swap/config.yaml` | llama-swap Config | -| `MC_GATEWAY_URL` | `http://127.0.0.1:$MC_PORT` | Builtin-Gateway (Teil von MC2, kein externer Dienst) | -| `MC_PORT` | `9000` | MC-Backend-Port | -| `MC_ENGINE_PATH` | `/opt/llamacpp-vulkan` | Aktive Engine-Binary (Vulkan-Build) | -| `MC_ENGINE_REPO` | `ggml-org/llama.cpp` | Quelle für Engine-Update-Check | -| `MC_DRAFTS_DIR` | `$MODELS/drafts` | Spec-Draft-Modelle (vocab-geprüft) | -| `MC_SPEC_TYPE` | `draft-simple` | Speculative-Decoding-Typ (llama.cpp) | +| `MC_PORT` | `9000` | MC-Backend-Port (**die Unit auf der Box setzt `9001`**) | +| `MC_LLAMA_SWAP_URL` | `http://127.0.0.1:8080` | Engine/Router | +| `MC_CONFIG_PATH` | `/etc/llama-swap/config.yaml` | llama-swap-Config | +| `MC_V1_UPSTREAM` | – | gesetzt → `/v1` geht an `mc2-gateway` (`:9010`) statt in-process | +| `MC_GOVERNOR_URL` | `http://127.0.0.1:8100` | Token-Wächter für die Cockpit-Kachel | +| `MC_ENGINE_PATH` | `/opt/llamacpp-vulkan` | aktive Engine (Vulkan-Build) | +| `MC_REWARM_ENABLED` | `1` | Warm-Set-Wächter (auf der Box bewusst `0`) | +| `MC_DRAFTS_DIR` · `MC_SPEC_TYPE` | `$MODELS/drafts` · `draft-simple` | Spekulatives Dekodieren | + +Governor-eigene Schalter (`GOV_THRESHOLD`, `GOV_HARD_CEILING`, `GOV_EXEMPT_MODELS`, …): +[`deploy/governor/README.md`](deploy/governor/README.md). + +## Weiterlesen + +| Dokument | Inhalt | +|---|---| +| [`docs/BEDIENUNG.md`](docs/BEDIENUNG.md) | Wie man MC2 benutzt | +| [`docs/RUNBOOK.md`](docs/RUNBOOK.md) · [`docs/DISASTER_RECOVERY.md`](docs/DISASTER_RECOVERY.md) | Betrieb, Störungen, Wiederherstellung | +| [`docs/HERMES_SETUP.md`](docs/HERMES_SETUP.md) | Hermes-Agent, Profile, Crons | +| [`docs/AUFTRAGSBUCH.md`](docs/AUFTRAGSBUCH.md) | Vorschlags-Inbox und das Ein-Klick-Gate | +| [`docs/wissen/VERDIKTE.md`](docs/wissen/VERDIKTE.md) | **Finale Technik-Entscheide — nicht neu aufrollen** | +| [`docs/wissen/FALLEN.md`](docs/wissen/FALLEN.md) · [`docs/wissen/OFFENE-FAEDEN.md`](docs/wissen/OFFENE-FAEDEN.md) | Stolpersteine · offene Punkte | +| [`deploy/opencode/README.md`](deploy/opencode/README.md) | Coding-Bahn: Mannschaft, Verteilung, Fallen | +| [`AGENTS.md`](AGENTS.md) | Arbeitsregeln für Agenten in diesem Repo | diff --git a/deploy/opencode/opencode.box.json b/deploy/opencode/opencode.box.json index 7eaed1e..08a8fc5 100644 --- a/deploy/opencode/opencode.box.json +++ b/deploy/opencode/opencode.box.json @@ -11,19 +11,31 @@ "models": { "coder": { "name": "coder — Bauen + Planen (Qwen3-Coder-Next, 51,5 t/s)", - "limit": { "context": 131072, "output": 16384 } + "limit": { + "context": 131072, + "output": 16384 + } }, "hermes": { "name": "hermes — Suchen (Qwen3.6-35B, immer warm, 69,6 t/s)", - "limit": { "context": 65536, "output": 8192 } + "limit": { + "context": 65536, + "output": 8192 + } }, "kritiker": { - "name": "kritiker — Gegenlesen (Devstral-2, Mistral, 15,0 t/s)", - "limit": { "context": 65536, "output": 8192 } + "name": "kritiker — Gegenlesen (Devstral-2, Mistral, 16k gedeckelt)", + "limit": { + "context": 16384, + "output": 4096 + } }, "heavy": { "name": "heavy — Nacht-Gutachter (gpt-oss-120b, verdraengt das warme Set!)", - "limit": { "context": 32768, "output": 8192 } + "limit": { + "context": 32768, + "output": 8192 + } } } } @@ -33,7 +45,10 @@ "agent": { "plan": { "model": "aibox/coder", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } }, "build": { "model": "aibox/coder", @@ -55,13 +70,19 @@ "mode": "subagent", "description": "Codebase schnell durchsuchen, Dateien finden, Fragen zum Code beantworten — nur lesen, laeuft auf dem immer warmen Hirn", "model": "aibox/hermes", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } }, "review": { "mode": "subagent", "description": "Kritischer Code-Review nach jeder Etappe (Pflicht laut AGENTS.md): sucht erfundene APIs/CLI-Flags, stille Abweichungen vom KONZEPT, fehlende Tests, toten Code — meldet Befunde, aendert nichts. Laeuft bewusst auf einer FREMDEN Modellfamilie (Mistral/Devstral statt Qwen), damit er andere blinde Flecken hat als der Coder.", "model": "aibox/kritiker", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } } } } diff --git a/deploy/opencode/opencode.pc.json b/deploy/opencode/opencode.pc.json index ef3026d..1173805 100644 --- a/deploy/opencode/opencode.pc.json +++ b/deploy/opencode/opencode.pc.json @@ -11,19 +11,31 @@ "models": { "heavy": { "name": "heavy — Planer (gpt-oss-120b, 32k)", - "limit": { "context": 32768, "output": 8192 } + "limit": { + "context": 32768, + "output": 8192 + } }, "coder": { "name": "coder — Bauen (Qwen3-Coder-Next, 131k)", - "limit": { "context": 131072, "output": 16384 } + "limit": { + "context": 131072, + "output": 16384 + } }, "hermes": { "name": "hermes — Erkunden (Qwen3.6, immer warm, 69,6 t/s)", - "limit": { "context": 65536, "output": 8192 } + "limit": { + "context": 65536, + "output": 8192 + } }, "kritiker": { - "name": "kritiker — Gegenlesen (Devstral-2, Mistral, 15,0 t/s)", - "limit": { "context": 65536, "output": 8192 } + "name": "kritiker — Gegenlesen (Devstral-2, Mistral, 16k gedeckelt)", + "limit": { + "context": 16384, + "output": 4096 + } } } } @@ -33,7 +45,10 @@ "agent": { "plan": { "model": "aibox/coder", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } }, "build": { "model": "aibox/coder", @@ -55,13 +70,19 @@ "mode": "subagent", "description": "Codebase schnell durchsuchen, Dateien finden, Fragen zum Code beantworten — nur lesen, läuft auf dem immer warmen Hirn", "model": "aibox/hermes", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } }, "review": { "mode": "subagent", "description": "Kritischer Code-Review nach jeder Etappe (Pflicht laut AGENTS.md): sucht erfundene APIs/CLI-Flags, stille Abweichungen vom KONZEPT, fehlende Tests, toten Code — meldet Befunde, ändert nichts. Läuft bewusst auf einer FREMDEN Modellfamilie (Mistral/Devstral statt Qwen), damit er andere blinde Flecken hat als der Coder.", "model": "aibox/kritiker", - "permission": { "edit": "deny", "bash": "deny" } + "permission": { + "edit": "deny", + "bash": "deny" + } } } } diff --git a/docs/wissen/VERDIKTE.md b/docs/wissen/VERDIKTE.md index bd4e2dd..87ef3c6 100644 --- a/docs/wissen/VERDIKTE.md +++ b/docs/wissen/VERDIKTE.md @@ -130,3 +130,19 @@ Gemessen mit llama-bench (Vulkan/RADV, Q4_K_M, -fa on) auf der Box (Ryzen AI Max Speed- und kein Backend-Problem und wird weder durch Modelltausch noch ROCm geloest. Es ist Reliabilitaet = Modellklasse + Harness. Naechster Hebel: Post-Edit-Verify-Hook, kleine Etappen/frische Threads, Eskalation der harten 20% an Frontier. +- **Devstral Small 2 ist der KRITIKER, nicht der Coder — mit hartem 16k-Deckel (25.07.).** + Das Verdikt „als Coder disqualifiziert" (24.07.) bleibt unveraendert richtig. Neu ist nur die + ENGE Rolle: Gegenlesen einer Etappe. Gemessen am 25.07. auf der Box: Generierung 15,0 t/s + (Coder 51,5), Prefill 265-318 t/s (Coder 754). Der Prefill bricht mit der Kontextlaenge ein + (32k -> 63 t/s = ~9 min nur zum Lesen), deshalb ist der Kritiker in llama-swap UND in beiden + opencode.json auf **16384** gedeckelt: schlimmster Fall je Review bleibt unter einer Minute. + Der Nutzen liegt nicht im Tempo, sondern in der FREMDEN Modellfamilie — ein Mistral-Modell hat + andere blinde Flecken als der Qwen-Coder. Alternative GLM-4.7-Flash (MoE, schnellerer Prefill) + bleibt eine Zeile Config entfernt, kostet aber ~9 Punkte SWE-bench (59,2 vs. 68,0). +- **llama-swap haelt nur EINE Gruppe resident, und `persistent: true` ist gefaehrlich (25.07.).** + Zwei ko-residente Gruppen verdraengen sich gegenseitig — alles, was gleichzeitig warm sein muss, + gehoert in DIESELBE Gruppe (`brains`). `persistent: true` hindert llama-swap daran, vor einem + grossen On-Demand-Modell abzuraeumen: mit 107 GB Warm-Set + Vision (20 GB) folgte ein + **Kernel-OOM** (llama-server abgeschossen). Regel: `Warm-Set + groesstes On-Demand-Modell + <= ~115 GB` UND `persistent: false`. Danach lud vision in 10 s statt 117 s + Absturz. + Kontext-Halbierung spart bei Qwen3-Next uebrigens **0 GB** (Hybrid-Attention, winziger KV).