Der "Hermes GUI"-Tab (iframe auf /hermes-ui/) und das Hermes-Terminal-ttyd
(:7681) entfallen — die Agent-Oberfläche ist jetzt die Hermes-Desktop-App,
die über den BESTEHENDEN MC2-Proxy /hermes-ui/ (WS inklusive) an die Box
andockt. hermes-builtin-ui (:9119) bleibt als Desktop-Gateway erhalten und
wird im Dienste-Drawer + /api/system/services erstklassig geführt (statt
hermes-terminal); Wartungs-Allowlist kann ihn jetzt neu starten.
- Frontend: Tab/View raus (nav.ts, App.tsx, TerminalView.tsx gelöscht),
AgentView + (Legacy-)AgentStatusCard zeigen Desktop-Gateway statt ttyd,
Dienste-Zeile hermes-terminal → hermes-builtin-ui, Versions-Zeile
"Hermes UI" (nesquena-Karteileiche ~/hermes-webui) entfernt.
- Backend: terminal_url/terminal_reachable + HERMES_TERMINAL_* raus,
console.py proxyt nur noch die Box-Konsole, /api/system/services führt
hermes-builtin-ui, USER_SERVICES getauscht, hermes-webui-GitInfo raus.
- deploy.sh: legt hermes-terminal + hermes-webui idempotent still
(disable --now + Unit-Löschung). deploy/hermes-terminal.service bleibt
EINEN Zyklus im Repo (das laufende alte deploy.sh kopiert es noch —
Selbst-Reset-Falle); Aufräum-Commit folgt nach dem nächsten Deploy.
- frontend/dist mit-committet (Box baut nicht selbst).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der letzte Meter des propose-only-Kreislaufs: Vorschlags-Branches (Werkstatt/
Orchestrator) und Traum-Skill-Kandidaten werden als API sichtbar; Annehmen laeuft
als detached systemd-Unit (Merge im Worktree -> Push main -> Deploy -> Health ->
Auto-Revert bei Rot). Dazu: Chronik-Endpoint (Announce-Store als Timeline),
Wissens-Vault-Reader (read-only, Traversal-Guard), Zeitmaschine (Snapshots +
detached Restore) und Morgenlage-Spiegel im Chef-Gutachter-Feed (priority=silent).
python-multipart explizit in requirements (voice braucht es, war implizit).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Befund 08.07.: 'hermes update' scheiterte real an einem verwaisten
.git/index.lock (git stash exit 1), aber der Job wurde GRUEN — das ';'
vor dem Dienst-Neustart (noetig, damit die gestoppte UI auch im
Fehlerfall wieder hochkommt) schluckte den Update-Fehler, und der
Postcheck bestand mit dem ALTEN Agenten. User sah 'done', Badge blieb
(125 Commits Rueckstand). Neu: RC wird festgehalten, Dienste starten
IMMER wieder, aber der Job uebernimmt den echten Update-RC und
schreibt eine Klartext-Zeile ins Log. Lock auf der Box entfernt
(Verwaisung von gestern 21:22, wie beim MC2-Repo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neuer POST /api/maintenance/update-all kettet die AUSSTEHENDEN Updates
sequenziell (Engine -> Router -> Hermes -> OS) in einem maintenance-Job.
Bewusst reine Wiederverwendung: jeder Teil ist exakt der Befehl des
Einzel-Updates inkl. dessen Backup/Postcheck/Selbst-Rollback; &&-Kette
stoppt beim ersten Fehler, Banner-Zeilen im Log zeigen den Schritt.
OS zuletzt (breitester Eingriff, braucht als einziges das Box-Passwort;
fehlt es, laufen die sudo-freien Teile trotzdem und OS wird uebersprungen).
Hermes-Befehlskette in _hermes_update_cmd() extrahiert (DRY).
UI (SystemDrawer/Updates): Button 'Alle aktualisieren (N)' neben der
Update-Suche, nur sichtbar wenn etwas aussteht, gesperrt waehrend ein
Wartungs-Job laeuft, mit Bestaetigungs-Dialog der die Kette benennt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die zwei neuen Rollen aus dem Rollen-Audit tauchen jetzt ueberall
ordentlich auf statt als namenlose Eintraege:
- ROLE_IDS (llamaswap + sources) um kritiker/reranker erweitert
- roleMeta.ts: 'Kritiker' (Scale, cyan — die unbestechliche Zweitmeinung)
+ 'Gedaechtnis-Sortierer' (ListOrdered, lime — Feinsortierung hinter
dem Gedaechtnis, direkt nach embed einsortiert)
- werkbank/roleColors.ts: Speicherleisten-Farben passend dazu
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User-Entscheid 07.07.: 'Gehirn + Embedding reichen komplett aus' — die Augen
(VL-30B, ~19 GB) werden nur gebraucht, wenn Lucy auf dem Desktop an ist oder
die IDE-Lane sie ruft. Warm-Set = nur noch Qwen3.6 + embed; damit passt der
60-GB-Chef-Gutachter (gpt-oss) wieder neben das Hirn.
- llama-swap.config.yaml: VL-30B aus brains raus, ttl 0 -> 900 (15 min
Nachlauf); Kommentare entstaubt. AUSSERDEM Template<->Live-Drift beendet:
Template hatte coder-lite wiederbelebt (live seit 05.07. entfernt) und
KV q4_k (lief NIE live) — beides auf Live-Wahrheit (q8_0, kein coder-lite)
zurueckgesetzt; Qualitaet vor ein paar GB, RAM-Engpass ist mit der Diaet weg.
- warmup.sh: Default 'fast vision' -> 'fast' (Root-Kopie unter
/usr/local/bin braucht spaeter einmal sudo cp — bis dahin waermt ein
llama-swap-Restart vision einmalig, ttl 900 raeumt es wieder ab)
- warmer.py: Docstring auf neues Warm-Set angepasst
- Lucy-Seite (eigenes Repo): App waermt die Augen beim Start + alle 10 min,
solange sie laeuft — Augen-Lebenszyklus == Lucy-Lebenszyklus
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vier verifizierte Befunde aus dem externen Review (Gemini 3.1 Pro):
- app.py: SPA-Fallback gegen Path-Traversal gehaertet (resolve + is_relative_to,
liefert nur noch Dateien INNERHALB von frontend/dist aus).
- app.py/gateway_proxy.py: geteilter httpx.AsyncClient im lifespan statt neuer
Client pro /v1-Anfrage (Keep-Alive/Pooling, spart Sockets unter parallelen Agent-Stroemen).
- system.py: check_versions_cached() mit threading.Lock + Double-Check gegen Scan-Stampede.
- AGENTS.md: Zeitzonen-Drift korrigiert (Box laeuft Europe/Berlin, nicht UTC).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
connect.py empfiehlt IDEs jetzt die realen Box-Modelle Coder (bauen) /
Planer (denken) / Augen (Bilder, images) direkt statt der "coding"-Lane
— deckt sich mit dem tatsaechlichen Zed-Setup. Zed-Snippet mit vollen
7-Feld-Capabilities + Provider "bosgame"; Kilo/Claude-Code auf model=coder.
coder-lite (Qwen3-Coder-30B) parallel aus der llama-swap-Config der Box
entfernt (war ungenutzt: coding-Lane nutzt ohne Policy immer den starken coder).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ursache des fehlgeschlagenen Engine-Updates: die allerneueste llama.cpp-Release traegt
oft noch KEINE CI-Binaries (0 Assets). update-engine.sh lud aber stur von releases/latest
→ 404 „Download fehlgeschlagen".
Fix:
- update-engine.sh: nimmt die neueste Release, die wirklich ein ubuntu-vulkan-x64.tar.gz
traegt, und nutzt dessen echte browser_download_url (robust gegen Namensaenderungen).
- maintenance.py: _engine_update_available + engine_update_details pruefen jetzt ebenfalls
gegen die neueste ASSET-tragende Release → das Badge luegt nicht mehr („verfuegbar", aber
Download 404). Verifiziert: aufgeloeste URL liefert HTTP 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Terminals (wie die Box-Konsole):
- hermes-terminal bindet jetzt NUR Loopback (--interface lo --base-path /hermes-terminal)
und wird von MC2 same-origin durchgereicht (routers/console.py generalisiert auf beide
ttyd-Instanzen). Kein eigener Firewall-Port mehr noetig.
- Beide Terminals starten die Shell/CLI ueber `su - hitonabi` → fragen beim Oeffnen das
Box-Passwort ab (PAM gegen das echte Konto, nichts gespeichert). „Login mit sudo-PW".
- agent_status.terminal_url = /hermes-terminal/ (+ reachable via Loopback-Check).
Engine-Update (llama.cpp) — Fix „nicht moeglich":
- update-engine.sh/update-swap.sh sind per sudoers NOPASSWD freigegeben → das fruehere
`sudo true`-Passwort-Gate hat sie faelschlich blockiert (wenn kein/falsches Box-PW). Gate
entfernt → Engine-/Router-Update laufen jetzt passwortlos.
OS-Update (apt) — Fix „nicht moeglich":
- DEBIAN_FRONTEND wird jetzt INNERHALB `sudo bash -c '…'` gesetzt statt `sudo VAR=… cmd`
(sonst lehnt sudos env-Policy die Variable ab und das Upgrade bricht ab).
- Frontend verschluckt password_required/incorrect_password nicht mehr still, sondern zeigt
einen klaren Hinweis (Box-Passwort in „Box-Zugang" setzen/pruefen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem: ttyd auf :7682 war von aussen per ufw geblockt (nur 7681/9001 offen), also
im Browser Timeout — und ufw oeffnen braucht sudo, das MC2 hier nicht passwortlos hat.
Fix: ttyd bindet jetzt NUR an Loopback (--interface lo, --base-path /console) und wird
von MC2 ueber den ohnehin offenen Port 9001 same-origin durchgereicht:
- routers/console.py: HTTP-Passthrough (index/token) + WebSocket-Bridge (tty-Subprotokoll
auf beiden Seiten) → /console/ + /console/ws.
- app.py: console.router VOR dem SPA-Catch-all eingehaengt.
- config: BOX_CONSOLE_UPSTREAM (127.0.0.1:7682) + BOX_CONSOLE_PATH (/console/);
agent_status liefert box_console_url=/console/ + reachable=Upstream-Check.
- deploy/box-console.service: --interface lo --base-path /console.
- vite: /console (ws:true) fuer die Dev-Vorschau geproxyt.
Kein Firewall-/sudo-Eingriff noetig; Konsole laeuft same-origin zum Dashboard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Kompletter Frontend-Umbau auf das abgenommene v3-Konzept, dazu zwei neue Funktionen.
Frontend (Neuordnung bestehender IST-Views, kein Backend-Umbau):
- Cockpit ist die neue Startseite: ruhige Bereichs-Kacheln (je 1 Live-Zahl +
Status-Punkt), ehrliche Status-Zeile "Box gesund" + Speicher-Pille, "Braucht dich"
(kritische Probleme mit 1-Klick-Reparatur + bereitliegende Updates).
- Modelle-Werkbank: Maschinenraum-Speicherleiste als Hero (Arbeitsspeicher-Balken,
nach Rolle eingefaerbt + frei), darunter Master/Detail. Eingebettet als Haupt-Tab
im Modell-Manager ("Werkbank"), "Modelle finden" + JobsBar bleiben.
- Sidebar/Nav neu strukturiert; alle Aktionen ueber die bestehenden /api-Endpoints.
Neue Features:
- Box-Konsole: zweites ttyd-Web-Terminal mit echter Login-Shell auf :7682 (direkter,
SSH-artiger Box-Zugriff, kein Passwort — gleiches LAN-Trust-Modell wie hermes-terminal).
Neuer Dienst deploy/box-console.service + agent_status-Felder box_console_url/-reachable.
- Box-Zugang: das Host-Sudo-Passwort laesst sich jetzt direkt in der Konsole-Seite
setzen/aendern/loeschen (lokal im Browser), statt nur versteckt im System-Drawer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
voice_metrics.py: neben den rollenden Stats jetzt ein echter Per-Turn-Trace
(TurnTrace + Ringpuffer der letzten 60 Turns). Balken-Stufen zeitlich disjunkt
(stt · vision · hirn · gen); hirn misst ab mark_brain_start() VOR dem Hermes-
Request, damit die Vision-Zeit nicht doppelt gezaehlt wird. STT (davor) und
Mem0-Retrieve (Rueckruf waehrend) werden per park()/_take_* best-effort dem Turn
zugeordnet (Ein-Nutzer-Geraet, kein Turn-ID noetig). Mem0 = Unter-Detail INNERHALB
hirn (nicht addieren) -> ehrlich, kein Doppelzaehlen.
voice.py: TurnTrace in voice_chat's gen() (commit garantiert 1x via finally, auch
bei Fehler/Abbruch). STT-Endpoint parkt seine Dauer. NEU: GET /api/voice/metrics
(schliesst die Luecke - selbstkritik-feed.sh curlte das, existierte nie -> 404) +
GET /api/voice/trace?limit=N.
memory.py: GET /api/memory?q=... (= Hermes' Mem0-Prefetch) misst + parkt die
Retrieve-Zeit.
Frontend: LatencyCard (gestapelte Balken je Turn, "Taeter" = groesste Stufe,
Fehler-Turns rot, Tooltip mit "davon Mem0 X s"), Query useVoiceTrace, in der
Zentrale unter "Stack & Telemetrie". Lokal gegen Seed-Server verifiziert: 30,3-s-
Haenger -> Hirn-Balken 94% + "davon Mem0 26,1 s".
Grenzen (ehrlich, als Fussnote in der Karte): Tool-Runden im Hermes-LLM-Loop haben
keinen Callback an MC2 -> stecken in "Antwort". Reine Telegram-Text-Turns laufen an
MC2 vorbei und erscheinen hier nicht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
set_group() setzte persistent:true (Verdraengungsschutz), aber NICHT ttl:0. persistent
schuetzt nur gegen Verdraengung durch andere Modelle, nicht gegen ttl-Selbstentladen →
ein Mitglied mit ttl>0 faellt trotz brains-Mitgliedschaft nach Leerlauf aus dem Warm-Set
(live: VL-30B mit ttl 300 entlud sich alle 5 Min). Jetzt erzwingt set_group bei persist=True
ttl:0 fuer jedes Mitglied → der Fehler kann beim Warm-Set-Umbau nie wieder passieren.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c) System-Logs ausgebaut: neue LogConsole-Komponente färbt Fehler (rot) und
Warnungen (amber) ein, "Nur Probleme"-Filter mit Zähler, Zeilen-Suche;
voice-service in die Dienst-Liste aufgenommen (war nur backend-seitig).
e) Mem0-Dubletten automatisch: deterministischer Auto-Dedupe-Loop (täglich,
apply=True, Schwelle 0.9 > manueller 0.85 da ohne Review) als Backend-
Hintergrund-Task — kein Memory-Bloat mehr ohne Zutun. Knopf bleibt on-demand.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auto-Rewarm (Nudge + Idle-Tick) lädt jetzt das GANZE Warm-Set über
deploy/warmup.sh nach (fast+vision via chat, embed via /v1/embeddings,
Agent-Prompt-Prefill) statt nur einen Brain-Ping. Erkennt TEIL-Kälte
(Mitglied fehlt in /running), nicht nur den komplett leeren Zustand —
genau der Fall nach einem watch-config-Reload/Deploy (Augen+Gedächtnis
fielen raus, Hirn blieb warm). deploy.sh ruft am Ende warmup.sh.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a) Update-Meldungen: generischer Release-Summarizer in Lucys Stimme mit
strukturiertem Aktions-Verdikt ("Musst du etwas tun? NEIN/JA") für
Hermes, Engine (llama.cpp) und llama-swap; Fangnetz-Hinweis verheiratet
Breaking-Change-Sorge mit dem Postcheck.
b) OS ehrlich: zurückgestellte Pakete (Phasen-Rollout / kept back) werden
ausgewiesen statt scheinbar zu hängen.
d) Ehrliche Speicher-Zahlen: KV-Cache aus echten GGUF-Architektur-Daten
(Layer × KV-Köpfe × head_dim) + KV-Quant aus dem cmd statt params-blinder
Schätzung — footprint_gb als eine Zahlensprache (Zentrale, Modell-Manager,
fits-Check auf warmset+largest). Auto-Rewarm-Nudge nach Config-Reload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_summarize_hermes_commits nutzt jetzt finish_reason: bei "length" (Token-Limit
erreicht) wird der unvollstaendige letzte Stichpunkt entfernt, bei "stop" bleibt
die Antwort unveraendert. max_tokens 380 -> 550 als Puffer.
Erster echter Werkstatt-Kreislauf (Gesellenpruefung), Runde 2 nach Review.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- services/announce.py: persistenter Briefkasten (/srv/models/mc2-announce.json),
POST /api/voice/announce + GET /api/voice/announcements (Cursor-Polling)
- services/sentry.py: Health-Wächter (Engine/Hirn/Hermes/Mem0/Voice/Platte),
flankenerkannt (Alarm nach 3 Fehl-Ticks, Entwarnung, 6h-Erinnerung),
meldet in Briefkasten + Telegram; Hirn-Verdrängung durch IDE-Last = kein Alarm
- notify.sh spiegelt jede Telegram-Meldung in den Briefkasten (Updates/Radar
erreichen damit auch die Desktop-Lucy)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live gefunden (Zed-Start warf Lucys Hirn raus): llama-swap ignoriert
unbekannte Group-Keys stillschweigend — der Verdrängungsschutz der
brains-Gruppe war seit jeher wirkungslos. set_group() schreibt jetzt
beide Keys (persistent für llama-swap, persist für MC2-API/UI),
budget.py rechnet die echte Ko-Residenz (on-demand reserviert das
Warm-Set statt 0), Warn-Texte beschreiben Überlauf statt Verdrängung.
Box-Config live gefixt + verifiziert: Coder und Qwen3.6 gleichzeitig ready.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Roo Code wurde April 2026 eingestellt (Repo archiviert) — Kilo Code ist der aktive
Nachfolger der Roo/Cline-Linie (Orchestrator-Modus, Modell-pro-Modus, JetBrains+CLI).
Cursor/Zed/Continue raus (cloud-first bzw. von Kilo abgedeckt). Kilo-Note enthaelt die
Modus-Zuordnung: Code->coding, Architect/Orchestrator->heavy, Ask/Debug->chat.
Das Evolution-Radar (AUTONOMIE_PLAN E4) ueberwacht die Tool-Kategorie kuenftig selbst.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Update-Job: nach 'hermes update' laeuft 'hermes doctor' (Job rot bei Fehlern)
- hermes-postcheck.sh: Journal-Scan auf Unknown/deprecated/defaulting (Lehre aus v0.18:
approvals.mode 'auto' wurde still ungueltig -> alle Tools in pending_approval),
Tool-Smoke (echo via Agent, erkennt pending_approval), Voice-Smoke (/api/voice/chat)
- Update-Modal: die Box fasst anstehende Hermes-Commits selbst zusammen (fast-Modell,
no-think, gecacht auf neuesten Hash) — Breaking Changes zuerst
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backend:
- MTP-Drafter-Support (Multi-Token-Prediction): erkennt MTP-Köpfe neben dem Modell
(mtp-*.gguf / *-assistant, arch gemma4-assistant), schreibt
--model-draft … --spec-type draft-mtp --spec-draft-n-max statt draft-simple.
_parse_model erkennt --model-draft/-md; drafts_for/set_spec_draft/find_compatible_draft
MTP-bewusst. Backward-kompatibel (klassische Drafts unverändert). (config.SPEC_DRAFT_N_MAX)
- register_model: cache-reuse/-cram als Default (Drift-Fix — neue Installs wie der
hand-getunte Box-Stand), --parallel 2 nur noch für coder (kein ctx-Halbierungs-Footgun),
Spec-Auto-Attach für alle Rollen self-guarding.
- budget.reserved_gb auf die VERIFIZIERTE llama-swap-Gruppen-Swap-Semantik angeglichen:
on-demand-Modelle verdrängen die brains-Gruppe und laufen allein (reservieren 0, voller
GTT); brains-Member reservieren nur die übrigen Member. Tote _persist_members entfernt.
Frontend:
- SpecDraftModal zeigt MTP-Drafter mit MTP-Badge (DraftInfo.mtp).
Docs:
- docs/OPTIMIZATION_PLAN.md: vollständiges Audit + Umsetzungs-Log (W1/W2 Warm-Set,
gemma ctx/fa/cache-reuse/MTP 52→70,8 t/s, fast --parallel 1, scout=GLM-4.6V-Flash),
alles live gegen die Box verifiziert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ROLE_IDS (llamaswap, sources) + UI-Rollenlisten (ModelBadges, Discover,
ModelBrowse, Cockpit-Slot-Grid) um `hermes` erweitert: gemma erscheint als
„Hirn", nicht mehr als scout.
- Neuer set_ttl-Helper; set_agent_brain erzwingt ttl:0 (neu + idempotent beim
Re-Setzen) und liefert eine weiche Budget-Warnung (kein Hard-Block) bei OOM.
- brain_status/brain_model_name: zeigen das echte Hirn (Rolle hermes / Hermes
model.default) statt hart `fast` (Bugfix Health-/Ready-Check).
- POST /api/models/{id}/role delegiert die Rolle `hermes` an den warm-bewussten
Flow (Alias + brains-Gruppe + ttl 0 + Hermes-Config + Gateway-Restart).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Beseitigt Redundanzen/Mismatches, die sich mit den Lanes angesammelt hatten:
- Modell-Manager: großen animierten SVG-Gateway-Graph (~310 Z.) entfernt —
Rolle→Modell deckt das Slot-Grid ab, Lanes der Lane-Editor, IDE-Config die
"Verbinden"-Seite. Cockpit-Brain-Switch raus → Verweis auf Hermes-Tab.
- Hermes: zweiten SVG-Graph + 4 Status-Kacheln durch einen ruhigen Box→Pfeil-
Fluss ersetzt (Terminal → Gateway → Hirn/Verdrahtung/PC), Stil wie "Verbinden".
- Hirn-Wechsel vereinheitlicht: nur noch im Hermes-Tab. Installiert = warm-bewusst
(/api/agent/brain/set), Alias = /api/agent/brain; Lane-Aliase chat/coding/fast/heavy.
- Terminologie auf Lane-Sprache: ConnectView "model auto" → chat/coding;
connect.py-Snippets defaulten auf 'coding' (GATEWAY_MODELS mit Lanes vorn).
- Zentrale: ActiveModelsCard + RolesCard zu einer ModelsCard verschmolzen
(Rollen + warm + Inferenz + Größe); Layout entdoppelt.
~600 Zeilen SVG-Graph-Code raus, 2 tote Karten gelöscht. Verifiziert:
npm run build (tsc strict) clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Teil 1: VoiceLatencyCard auf dem Dashboard (GET /api/voice/metrics, C2) —
zeigt STT/Vision/Chat-TTFB/TTS mit p50/p95/last + count.
Teil 2: UI-editierbare Routing-Policy. Neuer routing_policy.py (hot-reload JSON
unter MODELS_DIR/mc2-routing.json, Env=Defaults, atomarer Write, Validierung).
router_logic, gateway_proxy und gateway.routing_summary lesen jetzt live via
load_policy(); routing_summary ist lane-bewusst (chat/coding statt altem auto).
Neue Endpoints GET/PUT /api/routing/policy.
Teil 3: LaneEditor.tsx als ZONE im Cockpit (chat/coding-Aliase + Schwellen +
fast_no_think, Speichern/Default-je-Feld); Gateway-Node zeigt die Lanes.
Verifiziert: npm run build (tsc strict) clean, FastAPI TestClient (GET/PUT,
Validierung, Persistenz, Hot-reload durch die API), venv-Smoke (Routing).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neues services/voice_metrics.py (rollend, thread-safe, in-memory): misst STT,
Vision-Beschreibung, Chat-TTFB (Hermes-Stream) und TTS server-seitig. voice.py
instrumentiert die vier Stufen; GET /api/voice/metrics liefert avg/p50/p95/last
je Stufe. Macht aus Latenz-Vermutungen Messdaten — Anzeige folgt im Frontend (E).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Agentisches Coden (OpenCode/RooCode/…) hat immer großen Repo-Kontext; die alte
Regel routete >24k Zeichen auf heavy (Allzweck-122B) statt auf einen Coder =
Downgrade der Coding-Fähigkeit. Jetzt: coding -> CODER immer. Optionaler leichter
schneller Coder via MC_ROUTE_CODER_LITE (Phase 2b: Qwen3-Coder-30B), Eskalation
auf den starken Coder bei Architektur-Keywords / sehr großem Kontext.
Reason-Strings header-safe gemacht (kein U+2192 → Latin-1-Crash im x-mc-Header).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der :9001/v1-Gateway bietet zwei virtuelle Modelle an, die der Router auf echte
Modelle abbildet:
- coding → coder (Standard) · heavy (riesiger/architektonischer Kontext) ·
fast (triviale Nicht-Code-Kurzfrage)
- chat → fast/heavy (= bisheriges model:auto, weiter als Alias unterstützt)
router_logic.choose_for_lane() kapselt die Lane-Logik (Code-Indikatoren DE+EN,
damit echte Coding-Anfragen nie auf fast abrutschen). gateway_proxy routet die
Lane-Namen und listet sie in /v1/models, sodass IDEs einfach "coding" wählen.
Lucy/Hermes (:8642) bleibt unberührt — andere Ebene.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/api/health liefert jetzt brain:{role,model,ready} (echter /running-Check —
ein abgestuerztes/nicht geladenes Agent-Hirn 'fast' erscheint dort nicht).
Frontend zeigt 'Hirn offline (model)' + Amber-Punkt, statt dass der Ausfall
nur als App-Fehler ('Provider returned an empty stream') auftaucht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher kein Schutz: Doppelklick/zwei Tabs konnten zwei update-engine.sh parallel
starten → racende .bak-Sicherung + parallele llama-swap-Restarts + sich gegenseitig
als kaputt sehende Postchecks.
Backend: jobengine.start_job bekommt group-Tag + active_in_group(); os/engine/swap/
hermes-update sind group="maintenance" und lehnen einen Start ab, solange eines laeuft
({ok:false, status:"busy", running:<label>}). Schuetzt auch gegen parallele Sessions.
Frontend: laeuft ein Wartungs-Job, zeigt der Drawer ein Banner "Update laeuft: <label>"
und sperrt "Jetzt aktualisieren" + "Nach Updates suchen". Logs/Job-Fortschritt/Dienste
bleiben voll nutzbar (Dashboard nicht hart gesperrt). Busy-Antwort wird als Hinweis gezeigt.
Modell-Upgrades bleiben erlaubt (parallel unkritisch).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
update-engine.sh / update-swap.sh sichern jetzt den alten Build/die alte Binary
VOR dem Ueberschreiben (.bak), verifizieren nach dem Restart per stack-postcheck.sh
und rollen bei Fehler automatisch zurueck (Binary/Dir wiederherstellen + restart +
erneut pruefen). Exit-Codes: 0 = neuer Build verifiziert, 1 = fehlgeschlagen aber
Rollback ok (alter Stand laeuft wieder), 2 = Update UND Rollback kaputt.
Da die Skripte den Postcheck nun selbst fahren (um reagieren zu koennen), entfaellt
das `&& stack-postcheck` in engine/swap-update-job. OS-Update behaelt den reinen
Detect-Check (apt-Downgrade waere unsicher). Backups sind winzig (Engine 86M,
Swap 14M) bei 1.6TB frei.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher hatte nur das Hermes-Update einen echten Post-Check; OS/Engine/Router
liefen mit Exit 0 durch, auch wenn der neue Build den Stack zerschoss (gruener
Job trotz totem Stack). Neu: deploy/stack-postcheck.sh prueft nach jedem Update
funktional — llama-swap aktiv, /v1/models 200, ECHTE 1-Token-Inferenz auf dem
Hirn-Modell (beweist Laden+Generieren), MC2 /api/health engine_reachable, Mem0
erreichbar. Eingehaengt als `<update> && bash stack-postcheck.sh` in os/engine/
swap-update-job → Exit 1 macht den jobengine-Job ROT. Pendant zu hermes-postcheck.sh.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_os_upgradable zaehlte mit `grep -c upgradable`, os_update_details parste
`[upgradable from:]` — beides englisch. Auf der deutschsprachigen Box gibt apt
aber `[aktualisierbar von:]` aus → Zaehler 0 und leere Detailliste, obwohl
`apt list --upgradable` 7 Pakete zeigt. Fix: apt mit LC_ALL=C aufrufen, dann
ist die Ausgabe immer englisch und beide greifen wieder.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- _installed_engine_build matchte nur 'build: <hash> (N)' / 'bNNNN', aber der
aktuelle llama-server meldet 'version: 9821 (hash)'. Dadurch war installed_build
immer None → Engine-Badge fiel auf ungenauen mtime-Vergleich zurueck. Jetzt
praeziser Build-Nummer-Vergleich (latest > installed).
- .gitattributes erzwingt LF fuer *.sh/*.service/*.timer: die Box hatte
core.autocrlf aktiv und checkte deploy.sh mit CRLF aus -> 'set -euo pipefail'
wurde zu 'pipefail\r' (invalid option name), Deploy brach ab.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- engine_update_job leert jetzt _engine_cache nach Abschluss (on_done),
sonst zeigte das Dashboard bis zu 1h "Update verfuegbar" trotz erfolgter
Aktualisierung (1h-Cache wurde nie invalidiert wie bei den anderen Jobs).
- check_updates_job leert zusaetzlich _comp_cache, damit "Nach Updates suchen"
auch den Hermes-Status frisch prueft.
- Neu: GET /api/maintenance/update-details (os|engine|hermes) liefert, was
genau aktualisiert wird (apt-Paketliste, Engine Build X->Y + Release-Notes,
Hermes-Commits HEAD..origin/branch).
- Frontend: "Aktualisieren"-Buttons -> "Anzeigen"; oeffnen ein Detail-Fenster
mit den konkreten Aenderungen, erst "Jetzt aktualisieren" startet das Update.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wartungs-Tab im SystemDrawer neu strukturiert:
- UPDATES: eine einheitliche Liste (OS, Engine, Hermes-Agent, Modell-Upgrades) mit
Status + Aktion-Button, der nur aktiv ist wenn ein Update ansteht (statt Klick-Karten,
die sofort updaten). Konsistent mit der Dashboard-UpdatesCard.
- DIENSTE: neue Sektion, alle systemd-Units mit Status-Punkt (aus /api/system/services,
jetzt inkl. mem0-service) + Restart + Logs-Sprung.
- BACKUP: kompakt (letztes Backup + Snapshot-Button + Restore-Hinweis).
- GEFAHRENZONE: Reboot abgetrennt. Jobs nur wenn vorhanden.
Hermes-Update-Button: POST /api/maintenance/hermes-update -> Job (Backup -> `hermes update
--yes` (git pull + deps) -> hermes-gateway restart). Backend: hermes_update_job + USER_SERVICES
um mem0-service/hermes-terminal ergaenzt (Restart ging vorher nicht), mem0 in services-API.
Live verifiziert: Button hat Hermes d470ed0 -> 3b44a3c aktualisiert, Integration intakt
(memory.provider, Plugin laedt), Pre-Update-Backup angelegt, Drawer rendert fehlerfrei.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bug: UI zeigte nie ein Hermes-Update, obwohl die CLI eins anzeigte. Ursache: MC2 verglich
das neueste GitHub-RELEASE (frozen v2026.6.19) gegen das installierte Commit — Hermes wird
aber aus git main aktualisiert (`hermes update` = git pull origin <branch>), und main laeuft
den Releases voraus. Darum war update immer false.
Fix: _hermes_agent_update() macht jetzt git fetch + zaehlt Commits HEAD..origin/<branch>
(genau wie `hermes update --check`). update=true wenn behind>0; latest = origin-Kurzhash +
behind-Count. Tote Release-Helfer (_gh_latest, _commit_ts) + HERMES_AGENT_REPO-Import entfernt.
Verifiziert: MC2 == CLI (beide "Update verfuegbar, 1 Commit hinter origin/main").
Frontend (UpdatesCard) rendert components bereits korrekt — nur das Backend-Signal war falsch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>