Vierte Etappe. Der Client-Zustand hatte bisher keinen Ort: zwei handgebaute
useSyncExternalStore-Speicher, drei CustomEvent-Kanaele und ein localStorage-Griff
mitten in einem useState — verteilt ueber fuenf Dateien.
## Ein Store (Befund B-08/B-09)
app/store.ts (Zustand, 1,2 kB gzip) haelt genau vier Dinge: Bedienvorlieben
(Schiene, Expertenmodus, Palette), die Lage des Ereignisstroms und die
Meldungs-Warteschlange. Der Kopfkommentar nennt die Regel, nach der etwas dort
landen darf — und ein Test prueft sie: gespeichert werden AUSSCHLIESSLICH
Schienen- und Expertenmodus-Zustand, kein Strom, keine Meldungen, kein Geheimnis.
Der Metrik-Verlauf bleibt bewusst DRAUSSEN (lib/metricsStore.ts): Er nimmt ab P4
jede Sekunde einen Messpunkt entgegen, ein Store-Update pro Sekunde wuerde jede
abonnierende Komponente neu rendern.
Die drei CustomEvent-Kanaele sind ERSATZLOS weg — `grep -r dispatchEvent src`
liefert nichts mehr. Wer die Schublade oeffnen will, setzt `?system=`; wer springen
will, navigiert. Auch der letzte Rest von P2 (`mc-palette-open`) ist aufgeloest.
## Statusleiste (Spezifikation §4.1)
Der Zustand der Box stand bisher verstreut: die Ampel unten in der Sidebar, die
Auslastung nur im Cockpit, das aktive Modell nur im Modell-Manager. Wer in der
Konsole arbeitete, sah gar nichts.
Jetzt eine feste Leiste ueber allen Ansichten: Motor/Hirn-Ampel (klickbar zum
Agenten) · aktive Rolle + Durchsatz mit Sparkline · geteilter Speicher ALS BALKEN
(nicht als Prozent — 128 GB Unified Memory ist die Kernzahl dieser Box) · CPU/GPU
· Temperatur (ab 85 °C bernstein) · Betriebszeit · Token-Summe · Live-Anzeige.
Die Sparklines sind eigenes SVG, ~20 Zeilen. Fuer eine 56-Pixel-Linie waere eine
Diagramm-Bibliothek Verschwendung.
Dafuer neu im Backend: `uptime_s` in /api/system/status (psutil.boot_time).
Gehoert dorthin, weil die Box sich woechentlich selbst neu startet — dann ist
"laeuft seit 20 Minuten" die Antwort auf eine ganze Klasse von Fragen.
Liefert psutil nichts, steht dort None und die Leiste blendet das Feld aus,
statt eine Zahl zu erfinden.
## aria-live (Befund B-11) — und diesmal mit Absender
Im ganzen Frontend gab es KEIN einziges aria-live. app/shell/Meldungen.tsx ist
jetzt die eine Stelle fuer beilaeufige Rueckmeldungen; Fehler bekommen
`assertive` und bleiben stehen, alles andere `polite` und raeumt sich weg.
Wichtig: Die Region ist keine Attrappe. Gespeist wird sie von den Uebergaengen des
Ereignisstroms und vom Konsolen-Neustart (mit dem echten Grund aus ApiError.detail).
Der erste Verbindungsaufbau wird bewusst NICHT gemeldet — sonst begruesst jede
Seite den Nutzer mit "Verbindung wieder da".
## Ehrliche Anzeige statt stillem Altern (Befund B-15/B-18)
lib/events.ts fuehrt die Stromlage jetzt im Store: live · nachlauf · getrennt.
Beim Wechsel wird EINMAL invalidiert — vorher las relax() den Zustand erst beim
naechsten Refetch, nach einem Riss blieb die UI bis zu 150 s im langsamen Modus.
## Bahnbreiten-Deckel (Befund B-10)
Die Arbeitsflaeche endet bei 1600 px. Ohne Deckel zog sich das Cockpit auf einem
3440-px-Ultrawide auf ueber 3 000 px, waehrend die Wurzel-Schriftgroesse mitwuchs
und die Zeilen GROESSER statt lesbarer machte.
## Nebenbei
Der Buendel-Budget-Check aus P0 war fragil: `ls dist/assets/index-*.js | head -1`
kann den falschen treffen, weil Rollup auch kleine geteilte Module "index-*.js"
nennt (gemessen: ein 67-Byte-Chunk neben dem 374-kB-Einstieg). Er waere dann still
immer gruen gewesen. Beide Ampel-Dateien lesen den Einstieg jetzt aus index.html.
## Verifiziert im Browser
Statusleiste: alle Felder mit Live-Daten, "Laeuft seit 1 Std 10 min"
Backend abgewuergt -> Leiste springt auf "Nachlauf" UND die aria-live-Region
meldet "Verbindung zur Zentrale verloren" (polite)
Backend zurueck -> "Live", ohne Begruessungs-Meldung
Cockpit-Kachel -> /cockpit?system=logs, Schublade offen, Reiter "System-Logs"
Arbeitsflaeche -> max-width 1600 px
33/33 Tests gruen (7 neue fuer den Store) · ESLint 0 Fehler · tsc sauber ·
Einstieg 118 153 B gzip / Budget 125 000.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zweite Etappe. Kern: das Frontend traegt kein Geheimnis mehr, und es laeuft
nicht laenger als einziger Teil des Stacks ungeprueft durchs Gate.
## B-01 — Box-Sudo-Passwort: ersatzlos entfernt
Das Passwort lag im localStorage und reiste bei JEDEM mutierenden Request mit —
als Header `X-Sudo-Password` UND im JSON-Rumpf. Da /etc/sudoers den Dienst-Nutzer
mit `NOPASSWD: ALL` fuehrt, waere ein einziger XSS in der SPA Root auf der Box
gewesen.
AUF DER BOX GEMESSEN: `sudo -n true` laeuft durch. Das Passwort wurde also nie
gebraucht — es war reines Risiko ohne Gegenwert. Darum keine Umkonstruktion
(Sitzungs-Cookie o. AE.), sondern Loeschung, quer durch den ganzen Pfad:
frontend/src/lib/api.ts kein localStorage-Zugriff mehr
frontend/.../SettingsTab.tsx Eingabefeld weg, dafuer die Erklaerung warum
backend/routers/maintenance.py SudoReq entfaellt, 8 Endpunkte entschlackt
backend/services/maintenance.py _run() nutzt immer `sudo -n`
backend/services/jobengine.py keine stdin-Pipe mehr (DEVNULL)
`password_required` bleibt als ehrliches Signal: Verlangt sudo je doch ein
Passwort, ist das eine Konfigurations-Frage auf der Box — nichts, was man mit
einem im Browser geparkten Geheimnis uebertuencht.
## HuggingFace-Token: liegt jetzt auf der Box
Derselbe Fehler, kleinerer Radius. Neu: backend/services/geheimnisse.py — Datei
neben den anderen mc2-*.json, Rechte 0600, atomar geschrieben. Die Oberflaeche
erfaehrt nur, OB ein Token gesetzt ist, nie seinen Wert. Ein Schluessel-Allowlist
verhindert, dass ein fehlgeleiteter Request beliebige Felder hineinschreibt.
Prozess-Env (HF_TOKEN) hat Vorrang und wird als solche angezeigt.
Verifiziert gegen das lokale Backend: setzen/lesen/loeschen ok, unerlaubter
Schluessel wird mit Klartext-Grund abgewiesen, der Wert kommt nie zurueck.
## B-14 — Fehlermeldungen sagen jetzt, was los ist
api() warf `new Error("500 Internal Server Error")` und verwarf den Rumpf; der
eigentliche Grund aus FastAPIs `detail` erreichte die Oberflaeche nie. Neu:
ApiError mit status + detail, inklusive Validierungslisten und HTML-Fehlerseiten
(ein kaputter Rumpf darf die Meldung nicht in einen zweiten Fehler verwandeln).
Zwei Aufrufstellen zeigen den Grund jetzt statt "Fehler" (Discover, ModelBrowse).
## B-07 — Tests und Linter, ehrlich eingeordnet
Praezisierung gegenueber dem Audit: Die MC2-Ampel fuehrt bewusst GAR KEINE Tests
aus (dokumentiert: die Python-Dienste haengen an ML-Wheels, die echten Tests sind
Pruefstand + Box). Das ist fuer die Dienste richtig — fuer Frontend-Unit-Tests
nicht: die laufen in jsdom, brauchen weder Modell noch GPU, und sind in 1,3 s durch.
Vitest + Testing Library, 17 Tests in 3 Dateien
ESLint (flat config) + Prettier
Beides jetzt Teil der Ampel
Die Tests sind kein Feigenblatt: acht davon sind der Zaun um B-01 — sie beweisen,
dass api() weder Kopfzeilen noch Rumpf aus dem localStorage anreichert. Dazu eine
ESLint-Regel, die localStorage-Zugriffe auf Schluessel mit password/token/secret
im Namen hart abweist (an einer Probe verifiziert; harmlose Schluessel wie
mc_sidebar_collapsed bleiben erlaubt).
ESLint meldet 0 Fehler / 93 Warnungen. Die 18 Treffer der neuen React-Compiler-
Regeln (setState im Effekt, Ref-Zugriff im Render) sind ECHT, aber quer durch
10 500 Zeilen zu beheben ist P5-Arbeit. Sie stehen als sichtbare Warn-Liste statt
abgeschaltet — ein ab Tag eins rotes Gate ist kein Gate mehr.
## Nebenbefund, im Browser reproduziert: veraltetes Buendel nach Deploy
Ein Deploy ersetzt dist und startet den Dienst neu; offene Tabs behalten aber ihr
altes Start-Buendel, dessen Nachlade-Chunks nun fehlen — der naechste
Ansichtswechsel wirft. Galt schon fuer die 10 lazy Views, traf durch P0 nun auch
die Startseite. lib/veralteteVersion.ts faengt Vites `vite:preloadError` ab und
laedt EINMAL neu (Sperre in sessionStorage gegen Endlosschleife).
## Nachgemessen
Start-Chunk gzip 111 411 B · dist gesamt 1 480 097 B (beide im Ampel-Budget)
tsc --noEmit sauber · 17/17 Tests gruen · ESLint 0 Fehler
Im echten Browser gegen das lokale Backend geprueft: Einstellungen holen den
Token-Zustand von der Box, kein Passwort-Feld mehr, Knoepfe korrekt gesperrt,
beide Cockpit-Diagramme rendern (Achsen + Zeitachse sichtbar).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Systemaudit vom 27.08.2026. Alle Befunde gemessen, nicht vermutet.
VIER STILLE DEFEKTE
1. mc2-steward startete seit Wochen nicht (live: 207.609 Neustarts).
steward.py importierte services.memory, das beim Mem0-Ausbau geloescht
wurde -> ImportError bei jedem Start. Re-Warm- und Health-Waechter
waren damit tot.
2. Jedes Hermes-Update wurde automatisch zurueckgerollt.
hermes-postcheck.sh prueft vier Dinge, die es seit dem 07.08. nicht mehr
gibt (Sidecar :8765, /api/memory, memory.provider, mc2-memory-Plugin).
Die Checks konnten nicht gruen werden -> autoupdate.sh wertete jedes
Update als rot und rollte es zurueck. Checks ersatzlos entfernt; der
Tool-Smoke laeuft ohnehin durch den echten Agenten.
3. 7 von 12 Skills waren per Knopfdruck nicht startbar.
deploy.sh kopiert Skills mit tr '-' '_' nach ~/.hermes/skills/,
routers/skills.py gab Hermes aber den Ordnernamen MIT Bindestrich.
Der Knopf meldete Erfolg, ausgefuehrt wurde nichts. Neu: _hermes_name().
4. deploy.sh warf bei jedem Deploy die Live-Modellkonfiguration weg.
MC2 schreibt /etc/llama-swap/config.yaml selbst; die Repo-Datei ist nur
ein Abzug (ihm fehlt u.a. kritiker/Devstral). Jetzt: erst sichern, Diff
zeigen, dann kopieren. MC_DEPLOY_SKIP_SWAP_CONFIG=1 ueberspringt.
MEM0-AUSBAU VOLLENDET (Kriterium 3: 17 -> 0 Dateien)
- mem0_service/, mcp/mcp_memory.py und hermes/plugins/mc2-memory entfernt;
das Plugin schickte bei JEDEM Turn zwei 404-Requests an tote Routen.
- MEMORY_DB/MEM0_SERVICE_URL, _mem0_reachable(), MC_MEMORY_DB und
MC_MEM_DEDUPE_ENABLED aus Config/Router/Unit entfernt.
- mem0_ms war strukturell tot (park("retrieve") wird nirgends mehr
aufgerufen) -> aus Backend, API-Typ und Latenzkarte entfernt.
- Verbinden-Tab: tote Gedaechtnis-MCP-Leitung raus, Status-Kachel bleibt.
- AGENTS.md beschrieb Mem0 noch als aktiv - korrigiert.
GATEWAY-ROBUSTHEIT
- _proxy gab bei ungueltigen Payloads HTTP 500 (gemessen 5/5: Rohtext,
leerer Body, JSON-Liste, JSON-String, null) -> jetzt 5/5 HTTP 400.
- Bild-Weiche ohne Deckel: 10 Bilder x 2 Versuche x 240 s hielten den
Client bis zu 80 min. Neu: MC_CODER_IMAGE_MAX (4), Rueckfall auf die
Vision-Umleitung.
- /v1/models: nicht-JSON von der Engine gab 500 -> jetzt 502.
UNITS UND DEPLOY
- mc2-steward.service, dessen warmset-Drop-in und voice-service.service
fehlten im Repo, obwohl maintenance.py und stack-postcheck.sh sie
voraussetzen. 1:1 von der laufenden Box uebernommen.
- deploy.sh startete mc2-steward nie neu; restore.sh liess mc2-gateway und
mc2-steward mit alter Config weiterlaufen. Beide ergaenzt.
FRONTEND
- useEigenleben rief /api/eigenleben - existiert im Backend nicht und wurde
nirgends genutzt. Samt Typen entfernt.
- Anleitung beschrieb einen Gedaechtnis-Tab, den es nicht gibt.
- Abgeglichen: alle uebrigen 63 Frontend-Aufrufe treffen echte Routen, alle
5 SSE-Invalidation-Keys sind gemappt, keine ungefangenen Promises.
Gates: compileall gruen - ruff "All checks passed" - tsc gruen - vite build
gruen (dist aktualisiert) - Importe app/steward/gateway_app gruen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Intelligenz sitzt nicht mehr NEBEN dem Coden, sondern DRIN. Alles auf der
Box gemessen, nicht angenommen.
Stufe 1 — Speicher-Haushalt (llama-swap-Config, nicht im Repo):
Coder dauerwarm statt ttl 600 (Kaltstart 23 s -> 491 ms), Devstral als
'kritiker' verdrahtet, Swap 11 GB -> 0. Zwei Befunde: Kontext 131k->65k spart
bei Qwen3-Next 0 GB (Hybrid-Attention), und llama-swap haelt nur EINE Gruppe
resident -> alles Ko-Residente in dieselbe Gruppe. `persistent: true` verhindert
dabei das Freiraeumen vor grossen Modellen -> ausgeloester Kernel-OOM, behoben
durch persistent:false + TTLs (Vision laedt jetzt in 10 s statt 117 s + Absturz).
Stufe 2 — Governor v2 (deploy/governor/):
Steht jetzt IM Pfad (:8100 -> MC2 :9001) statt daneben. Zaehlt den GANZEN
Anfragekoerper inkl. tools/tool_calls und kalibriert sich aus den echten
usage.prompt_tokens jeder Antwort nach: Schaetzfehler 200 % -> 0,3 %.
Soft-Einschub nur noch, wenn die Nachrichtenkette es erlaubt (kein Dazwischen-
funken in offene tool_calls). Neuer Status-Endpunkt + systemd-Unit.
Lucys Alltagsmodelle sind vom Schnitt ausgenommen.
Stufe 3 — OpenCode-Plugin (deploy/opencode/plugin/mc2-governor.ts):
Werkzeug-Zaun (git push, rm -rf, sudo, curl|sh — bewiesen), Pruef-Tor auf
session.idle mit Selbstreparatur, Savepoint statt Kompression, Meldungen an
Lucys Briefkasten mit eigenem Absender 'loop'.
Stufe 4 — Mannschaft (opencode.json):
plan+build -> coder (51,5 t/s) · explore -> hermes (69,6 t/s, warm, gratis) ·
review -> Devstral (15,0 t/s, FREMDE Modellfamilie gegen blinde Flecken).
Der 63-GB-Planer faellt aus der Tagesrolle raus.
Stufe 5 — ein Regelwerk, zwei Ausloeser:
deploy/opencode-lauf.sh faehrt dieselbe Bau-Pruef-Schleife unbeaufsichtigt
(die Schleife liegt hier UND im Plugin: bei `opencode run` endet der Prozess,
bevor session.idle fertig ist — gemessen). Bricht ab, wenn der Governor fehlt.
gitea-repo-create.sh saet jetzt VERIFY neben der CI-Ampel: jedes neue Repo
wird mit Innen- UND Aussen-Pruefung geboren.
Oberflaeche:
Token-Waechter-Kachel im Cockpit (Fuellstand, Marken, Ehrlichkeits-Nachweis),
/api/governor als gleichursprüngliches Fenster, Devstral im Modellkatalog,
Rollen-Texte auf die neue Mannschaft aktualisiert.
.gitattributes: deploy/**/*.py auf LF (deploy/*.py greift nur eine Ebene tief).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drei Luecken, die die neue Idee-Bahn unbrauchbar machten (User-Fund 21.07.):
1. Konzept unsichtbar. Der projektstart-Worker folgte dem Ende des
konzept-fliessband-Skills (Kopie nach ~/konzepte + Telegram) statt seiner
SOUL (Repo + KONZEPT.md) und schloss die Karte ab. Die Konzept-Ansicht sucht
nur in Gitea -> "noch kein Repo hinterlegt", obwohl das Konzept fertig war
(zweimal passiert: arm-ui, pomodoro-timer). konzept_of() faellt jetzt auf
~/konzepte/*.md zurueck (Pfad aus der Abschlussmeldung, sonst ueber den Titel
geraten; streng auf dieses Verzeichnis begrenzt) und nennt die Quelle.
Zusaetzlich sagen SOUL und Skill jetzt ausdruecklich, dass die Skill-Ablage
fuer Kanban-Worker NICHT das Ende ist.
2. Modus nicht erkennbar. Idee und IDE-Projekt trugen dasselbe "IDE"-Abzeichen,
Box-Karten gar keins. list_queue() liefert jetzt `art` (aus dem Body-Marker
AUFTRAGS-ART: IDEE PRUEFEN), die UI zeigt BOX / IDEE / IDE mit Erklaerung —
plus eine immer sichtbare Zeile, wann man welchen Modus nimmt.
3. Idee war eine Sackgasse. Neu: POST /api/ideen/weiterfuehren legt aus einer
fertig durchdachten Idee eine IDE-Projekt-Karte an — verkettet an die Idee,
mit dem fertigen Konzept als Vorlage ("denk es NICHT neu"), Titel aus der
Konzept-Ueberschrift statt aus dem Rohtext. Liegt das Konzept schon in einem
Repo, wird genau dieses weitergenutzt statt ein zweites anzulegen.
In der UI sitzt der Knopf unter dem gelesenen Konzept (Ziel + Aufwand).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
IDE-Vorbereiten-Karten bekommen einen 'Konzept'-Knopf: MC2 holt KONZEPT.md
aus dem vorbereiteten Gitea-Repo (Gitea-Raw-API + Auth aus git-credentials)
und rendert es direkt im Auftragsbuch (leichter MD-Renderer lib/markdown.tsx).
So liest der Commander das ausgearbeitete Konzept in der GUI, ohne das Repo
aufzumachen (User-Wunsch: 'lesen gehoert in MC2, feilen in die IDE').
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neue Intake-Weiche Box/IDE. IDE-Ideen gehen direkt an das neue Profil
'projektstart' (am Triage/Auto-Zerleger vorbei, kein Werkstatt-Bau): es
haertet via konzept-fliessband ein Konzept, legt ein leeres Gitea-Repo an
und fuellt es NUR mit Doku (Konzept/Roadmap/AGENTS.md/.aiexclude). Ergebnis
ist ein vorbereitetes Projekt, das der Commander in Zed selbst baut.
UI: Toggle 'Box baut / Ich bau in Zed', IDE-Badge auf Karten.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Karten lassen sich gezielt anhalten (generischer Block + Prozessbaum-Kill),
frisch starten (Retry beendet Worker samt Kindern - uvicorn-Falle) und per
Prio-Pfeilen umsortieren (Dispatcher zieht priority DESC nativ). Laufende
Karten ohne Heartbeat >10 min bekommen ein Warn-Badge; der Ketten-Digest
alarmiert nach 15 min per Telegram, inkl. Kontext-Verdichtungs-Hinweis.
Ausloeser: Scaffold-Worker hing 45 min an selbst gestartetem uvicorn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paket 1 - Metrik-Historie mit Zeitachse (User: 'WANN war Last?'):
- services/metrics_history.py: 10s-Sampler (CPU/RAM/GPU/Disk + Token-Totale) in
24h-Ringpuffer (aelteres faellt automatisch raus, nichts waechst unbegrenzt),
persistiert alle 5 min -> uebersteht Deploys; GET /api/system/history?minutes
mit Downsampling auf ~300 Punkte; Lifespan-Task in app.py
- Cockpit-Karten System-Status + Token-Durchsatz: Bereichs-Schalter Live/1h/24h,
sichtbare Zeitachse (HH:MM:SS bei kurzen, HH:MM bei langen Fenstern), Tooltip
zeigt Uhrzeit; Token-Raten in 1h/24h aus Totale-Deltas
Paket 2 - Verbinden selbsterklaerend:
- Box-IP vorbefuellt aus window.location.hostname (Dev-Fallback bleibt)
- MCP-Scriptpfad-Feld aus der Kopfzeile in die 'Gedaechtnis anbinden'-Karte
verschoben, mit Erklaerung WANN man es braucht
Paket 3 - Modelltausch-Loecher gestopft (Review 16.07.):
- install: Registrierung OHNE Alias-Umzug; Rolle wird erst NACH erfolgreichem
Download uebernommen (on_done) - hermes dabei durch den warm-bewussten
set_agent_brain-Flow statt rohem Alias-Move (Lucy waere sonst bis Download-
Ende tot gewesen); Re-Install erhaelt bestehende Aliase
- set_role_alias: lebenswichtige Aliase (hermes/embed) des Ziel-Modells
ueberleben jeden Rollen-Klick (Qwen3.6 haelt live hermes+fast!)
- Rollen-Endpoint verweigert Rollen-Wechsel am Halter geschuetzter Aliase
mit klarer Anleitung; Werkbank sperrt die Rollen-Chips sichtbar
Verifiziert: py_compile + Sampler-Smoke (2 Punkte, Persist ok) + Alias-Logik-
Unittest (3 Faelle) + Browser (Zeitachse tickt, Schalter, Leerzustand, Verbinden).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User-Feedback 15.07.:
1) 'Von allein' heisst jetzt 'Skills' (id #eigenleben bleibt, Links halten).
2) Jeder Skill traegt aktiv/inaktiv - Quelle ist Hermes' EIGENE Wahrheit
(hermes_cli.banner.get_available_skills via Hermes-venv, dieselbe Logik
wie das eingebaute WebUI: Plattform/Voraussetzungen/Config). Bewusst NUR
die Datenquelle wiederverwendet, nicht deren UI - Skill-VERWALTUNG bleibt
im Hermes-GUI-Tab, alles andere waere Bloat/Doppelbau.
3) Auftragsbuch: fertige Queue-Karten sind aufklappbar und zeigen das
ERGEBNIS des Workers (kanban_complete-Summary, lazy via
GET /api/ideen/{id}/ergebnis) - 'Dinge werden getestet, ich sehe aber
das Ergebnis nicht' ist damit zu.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die mitgelieferten Hermes-Skills sind Kategorie-Ordner (DESCRIPTION.md +
Unter-Skills mit eigener SKILL.md) - der Walker lief nur ueber Ebene 1
und zeigte 12 statt ~40 Skills. Jetzt beide Ebenen, Unter-Skills mit
Kategorie-Badge; Detail-Endpunkt erlaubt Kategorie/Name-Pfad.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User-Wunsch 15.07.: EIN Viewpoint, was die Box selbst geleistet hat -
Chronik ist zu kompliziert. Neue Operativ-Ansicht #eigenleben:
- Skills aus ~/.hermes/skills (= Lucys Satz) mit Klartext-Beschreibung,
Nutzungszaehler (.usage.json) und Herkunft (selbst erstellt / von uns
gebaut / mitgeliefert), aufklappbar mit vollem SKILL.md.
- Vorschlags-Bilanz: angenommen (Auftragsbuch-Chronik) + abgelehnt mit
Grund (Lern-Journal) als eine Timeline + Zaehler.
Backend: services/eigenleben.py + routers/eigenleben.py (read-only).
Mit an Bord (User-Ja, SCHLAFEND): config.V1_UPSTREAM + app.py-Weiche +
gateway_forward aus dem P1-Gateway-Auszug - ohne MC_V1_UPSTREAM in der
Unit exakt altes Verhalten. Der aktive Rest von P1 kommt separat ueber
Branch umbau/p1-gateway-auszug (dort liegt auch diese View schon).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sackgasse behoben: ein Worker blockte eine Aufgabe mit einer Frage
(kanban block --kind needs_input), aber die Zentrale zeigte nur den
roten Status "haengt - braucht dich" - ohne die Frage und ohne
Eingabefeld. Der Worker blieb so dauerhaft stehen.
Backend (services/ideen.py):
- _blocker_frage(): liest die Worker-Frage aus dem juengsten
blocked-Event (payload.reason/kind), Fallback: BLOCKED:-Kommentar.
- list_queue() reichert blockierte Karten mit frage + frage_kind an
(max 6 Extra-show-Aufrufe pro Poll).
- answer_task(): unblock --reason schreibt die Antwort als Kommentar
und stellt die Karte auf ready -> Dispatcher spawnt den Worker neu,
der die Antwort im Kontext vorfindet. Mit ID-/Laengen-Validierung.
Router: POST /api/ideen/antwort.
Frontend (AuftragsbuchView): blockierte Karten zeigen die Frage
(je nach Grund "Die Box hat eine Frage:" / "kam hier nicht weiter:")
plus Antwortfeld + "Antworten & weiter". Fallback-Text ohne Grund.
Vertraegt sich mit dem Live-Log-Blick (nur triage/running).
Verifiziert: E2E gegen die echte Box-Kanban-CLI (Frage auslesen,
answer_task entsperrt + protokolliert, Fehlerpfade), py_compile +
Frontend-Build gruen, Antwort-UI im Dev-Server gerendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix: 'Interaktives Terminal' im Cockpit führte ins Leere (#terminal) → Konsole
- Mobile: Off-Canvas-Sidebar mit Hamburger unter md, Inhalt volle Breite
(vorher: 240px starre Sidebar, 135px Rest mit Quer-Scroll auf dem Handy)
- Dead Weight raus: src/mc3/ (verworfener Prototyp), DashboardView (alte
Zentrale) + 6 nur dort genutzte Karten, 8 ungenutzte npm-Pakete
(three, three-vrm, react-three fiber/drei, sigma, graphology ×2, @types/three)
- Code-Splitting: alle Views außer Cockpit per React.lazy → Haupt-Bundle
983 → 739 KB, jede View ein eigenes Chunk
- Fonts lokal (@fontsource) statt Google-CDN → UI offline identisch
- Polling harmonisiert: EINE Takt-Tabelle in queries.ts (Graphen 3s, Rest
8-60s), keine Override-Intervalle mehr in Komponenten; Updates-Check
(apt/git!) von 4s auf 60s
- CSS-Hack-Layer aufgelöst: !important-Klassen-Sniffing → explizite
.mc-card/.mc-card-sm/.nav-active-Klassen (Look identisch, ungeschichtete
Regeln statt Utility-Raten); totes .light-Theme raus; Scrollbars 1× definiert
- Aurora: animierte Fullscreen-Blur-Filter → statische radial-gradients
(gleicher Look, keine Dauer-GPU-Last)
- Sicherheit: Sudo-Passwort/HF-Token nur noch bei mutierenden Requests,
nicht mehr auf jedem GET-Poll
- Strg+K statt ⌘K auf Windows; dist neu gebaut
Live gegen die Box verifiziert: alle 10 Views + Mobile-Flow, 0 Konsolen-Fehler.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Anlass: feature/cleanse-skill-index — ein Werkstatt-Worker hatte git init statt
Klonen gemacht (Orphan-Commit ohne gemeinsamen Vorfahren, Inhalt: ~/.hermes-Index-
Dateien statt Repo-Dateien). Solche Karten sahen aus wie normale Vorschlaege,
liefen bei Annahme aber IMMER in 'refusing to merge unrelated histories' — und
die Fehlermeldung ('bitte am PC aufloesen') war eine Sackgasse. Das passiert
oefter; darum drei Schichten dagegen:
1) ERKENNEN (Auftragsbuch): neue Karten-Flags 'verwaist' (kein merge-base mit
main -> rote Markierung 'kein gemeinsamer Ursprung', Annehmen-Knopf fehlt,
API+Runner halten zusaetzlich dicht) und 'leer' (Diff gegen main leer ->
'bringt nichts'-Badge). Empfehlung auf der Karte: ablehnen mit Grund,
Idee frisch in die Queue.
2) HEILEN (beide Runner, mc2 + lucy): kollidiert der Merge, weil main weiter-
gelaufen ist, versucht der Runner automatisch einen Rebase des Branches auf
main (isolierter Worktree; Gates laufen danach normal, Merge-Message sagt
'auto-rebased'). Nur wenn auch der Rebase kollidiert, faellt die Karte durch —
mit ehrlicher Meldung statt 'am PC aufloesen'.
3) VERHINDERN (werkstatt-SOUL): voll klonen (nie git init/--depth), Selbstcheck
'git merge-base HEAD origin/main' + fetch/rebase vor JEDEM Push, nie
~/.hermes-Artefakte committen.
Doku: AUFTRAGSBUCH.md + FALLEN.md (Erkennungsmuster: Diff 0 Dateien + behind ~
ganze Historie) + OFFENE-FAEDEN. Geprueft: py_compile gruen, bash -n beide
Runner gruen, tsc+vite build gruen (dist dabei); merge-base-Verhalten am echten
kaputten Branch auf der Box verifiziert.
User-Auftrag 12.07. ("bau das alles ein im Sinne der Autonomie. Auch muss
Lucy selbst bemerken wenn sich etwas aendert"):
- deploy/selbst-inventur.sh (Cron 03:35): SELBST-STECKBRIEF wird LIVE aus
der Realitaet GENERIERT (Versionen, Dienste, Timer, Modelle, Crons,
Queue, Karten -> ~/.hermes/state/selbst-steckbrief.md) statt von Hand
gepflegt. Diff gegen gestern => die Box BEMERKT SELBST Aenderungen an
sich (stille Chronik-Karte + kurze Telegram-Zeile; sonst still).
- deploy/karten-gutachter.sh (Cron 04:00): stempelt jede neue Karte mit
"Empfehlung: ANNEHMEN/ABLEHNEN/UNKLAR + ein ehrlicher Satz" (prueft
Redundanz gegen den Steckbrief, Risiko, Nutzen; Ein-Schuss-Richter
gpt-oss/GLM; Stempel = Meinung, kein Gate; neuer Commit entwertet den
alten Stempel). Backend mischt den Stempel in /api/auftragsbuch,
UI zeigt ihn farbig auf der Karte.
- Ablehnen mit Grund (Lern-Klick): UI-Inline-Feld beim Ablehnen ->
/srv/models/mc2-ablehnungen.jsonl -> Idle-Radar bekommt die Gruende
als "NIE wieder vorschlagen"-Material vorgelegt.
- idle-radar-feed.sh: Material + Raster erweitert um Selbst-Steckbrief,
Inventur-Diff und Ablehn-Gruende (Fehlerfall 12.07.: redundanter
Gateway-Restart-Vorschlag waere damit gestorben).
- werkstatt-SOUL Regel 7 + wartung-Skill: REALITAETS-CHECK - existiert es
schon? Dann kanban_block statt Branch (ein Branch fuer Ueberfluessiges
ist ein gescheiterter Lauf).
- hermes-release-radar-feed.sh: echter Treffer legt zusaetzlich EINE rohe
Idee in die Queue (idempotent je Release-Tag) - der Blick nach draussen
fuettert denselben Kreislauf.
- deploy.sh: kopiert beide neuen Skripte; Doku AUFTRAGSBUCH.md +
wissen/OFFENE-FAEDEN.md; frontend/dist frisch gebaut (tsc+vite gruen,
UI gegen Live-Box verifiziert).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Das Auftragsbuch-Gegenstueck fuer Lucy (Abloesungs-Paket S3, PC-Annahme-Weg):
- backend/services/auftragsbuch.py: Multi-Repo (mc2 + lucy via ~/lucy-Clone).
Karten tragen repo-Feld; Status-Schluessel fuer Lucy = 'lucy:<branch>';
fehlt ~/lucy, werden Lucy-Karten still weggelassen. Runner je Repo.
- deploy/lucy-annahme.sh: detached Annahme-Runner fuer Lucy-Karten.
Vorpruefung am PC VOR dem Merge (Executor erreichbar, Arbeitskopie main+clean,
laeuft Lucy?), dann Merge im isolierten Worktree von ~/lucy -> Push main ->
PC zieht ff-only und baut detached (deploy/lucy-annahme.ps1 im Lucy-Repo),
Box pollt .lucy-annahme.json und spiegelt Fortschritt auf die Karte.
Rot = Merge automatisch revertiert, laufende Lucy bleibt die alte.
Executor-Zugang (URL+Token) kommt aus ~/.hermes/config.yaml — kein zweiter
Ablageort. Neustart nur, wenn Lucy vorher lief (User-Entscheid).
- Router/UI: repo-Parameter (rueckwaertskompatibel, Default mc2), rosa
Lucy-Badge, eigener Annahme-Confirm-Text, Diff/Ablehnen je Repo.
- werkstatt-SOUL: Lucy-Auftraege ebenfalls propose-only, bauen macht der PC
bei der Annahme.
- Doku: docs/AUFTRAGSBUCH.md (Lucy-Annahme-Kapitel), docs/wissen/OFFENE-FAEDEN
(S2 erledigt, S3-Stand).
Geprueft: py_compile gruen, bash -n gruen, tsc+vite build gruen (dist dabei).
- Backend: check_health() prüft jetzt auch Desktop-Gateway (GET /api/status :9119)
- Frontend: ConnectHealth-Typ erweitert, dritte Status-Zeile mit emerald-Theme
- Frontend-Build: neu gebaut mit Vite (Hash-Dateinamen aktualisiert)
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>
Neue Views: Auftragsbuch (Karten mit Diff/Kritiker-Kontext, Annehmen/Ablehnen mit
Fangnetz-Dialog), Chronik (Tages-Timeline aus dem Briefkasten + Zeitmaschine mit
Ein-Klick-Restore), Wissen (Vault als klickbares Wiki, [[Links]] springen).
Cockpit: Auftragsbuch-Kachel + Braucht-dich-Eintrag, Morgenlage-Karte (juengstes
Chef-Verdikt), Anstehendes (Erinnerungen anlegen/loeschen), Wissen/Chronik-Kacheln.
Gedaechtnis: Dubletten-Dialog zeigt jetzt konkret, was bleibt und was wegfaellt.
dist mitgebaut (tsc+vite gruen).
Co-Authored-By: Claude Fable 5 <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>
f) Lucy/Voice-Reste aus dem MC2-Web-UI entfernt (kein "Sprechen"-Tab mehr):
VoiceLatencyCard + Sprach-Latenz-Plumbing (queries/api-Typen) und der
Backend-Leseendpoint /voice/metrics raus. Der Proaktivität-/Alarm-Kanal
(/voice/announce, /alarm) und die STT/TTS/chat-Proxys bleiben unberührt.
C15) README auf den Final-/Autonomie-Stand aktualisiert (Mem0 statt SQLite-MCP,
live+eingefroren, Lucy als eigenes Repo, Fangnetz-Updates/Werkstatt).
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>
tsc bestaetigte exakt die vom Werkstatt-Gate angekuendigte Luecke (4x TS2339 unit)
-> ServicesResp.services um unit ergaenzt, Build gruen.
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>
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>
Verhindert versehentliches Verdraengen des warmen Hirns im Modell-Manager.
- api.ts: GroupsResp-Typ + getGroups/setGroup (PUT /api/groups).
- queries.ts: useGroups-Hook (qk.groups).
- Cockpit: pro Modell ein "Brain"-Schalter (Ko-Residenz in der brains-Gruppe
an/aus) + "Ko-resident"-Badge. Beim Laden eines gruppenlosen Modells, das
ein warmes brains-Mitglied rauswerfen wuerde, erscheint eine Bestaetigung
mit Hinweis auf den Schalter (beide warm halten).
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>
- 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>
Paket B des Plans. AnythingLLM war nur ein Fallback-Chat zu Hermes; ersetzt durch das
echte interaktive Agent-Terminal (`hermes chat`, mit Tools/PC) als eingebettetes
Web-Terminal.
Box: ttyd (apt) wrappt `hermes chat`; systemd-User-Unit deploy/hermes-terminal.service
(LAN-Bind eno1:7681, apt-Default-ttyd-Dienst deaktiviert). In deploy.sh verankert.
Backend: config HERMES_TERMINAL_URL statt ANYTHINGLLM_URL/_REPO; agent_status liefert
terminal_url/terminal_reachable; maintenance ohne _anythingllm_update; system.py Dienst-Liste
zeigt "Hermes-Terminal".
Frontend: neue Terminal-Seite (iframe auf ttyd) + Nav-Tab; AgentView/AgentStatusCard/nav/api
auf Terminal umgestellt; SystemDrawer toter hermes-dashboard raus, hermes-webui -> hermes-terminal;
Guide-Texte aktualisiert.
Cleanup: deploy/hermes-webui.service + deploy/lobechat/ entfernt (LobeChat-Migration hinfaellig),
HERMES_WEBUI_URL-Env raus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Analog zum Auto-ctx-Button: das Rollen-Zuweisungs-Modal empfiehlt jetzt, welches
INSTALLIERTE Modell am besten auf die Rolle passt - capability-getrieben (Vision/Coder/
Tools/MoE aus services.caps) + setup-bewusster Fit (services.budget, gleiche Mathematik
wie Install-Automatik & Auto-ctx).
- services/roles.py: recommend_for_role() rankt installierte Modelle (Eignung + Fit + Tempo
+ Wissen); harte Anforderungen (Vision braucht Vision, Hirn braucht Tools) schliessen aus.
- GET /api/roles/{role}/recommend
- Cockpit-Modal: »Auto: <Modell>«-Button im Header, »Empfohlen«-Badge, Sortierung nach Score,
pro Zeile Fit + Begruendung (~t/s); ungeeignete gedimmt mit Klartext-Grund.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher rechnete nur der Hirn-Wechsel setup-bewusst; die allgemeine ctx-Auto-Groesse
nahm den Gesamt-RAM in ISOLATION (ignorierte Hirn/warmes Set/Ko-Residenz) -> ctx
konnte zu gross gewaehlt werden.
Neu: services/budget.py buendelt GTT-Budget, Modell-Footprint und reservierten Speicher
gemaess VERIFIZIERTER Box-Residenz (Hirn immer resident; fast/vision duerfen weichen,
wenn grosses on-demand-Modell laedt). setup_aware_ctx() bemisst den groessten ctx, der
NEBEN dem bestehenden Setup passt - rollen-/gruppen-bewusst aus der echten Config.
- fit.py: max_ctx_in_budget() als budget-basierter Kern; max_ctx_for() delegiert
- models.py: install nutzt setup_aware_ctx; /api/fit liefert assigned_ctx + Budget-Herleitung
- agent.py: nutzt die gemeinsamen Helfer (entfernt Duplikate _gtt_budget_gb/_foot)
- AddModel: Ampel zeigt den setup-bewussten ctx ('ctx -> Nk') inkl. Budget-Tooltip;
Rollen-Wechsel laedt die Vorschau neu (Rolle bestimmt das Budget)
Effekt: heavy-122B bekommt z.B. 16k statt 131072 (passt neben dem Hirn), waehrend
warme Kleinmodelle weiter grossen Kontext erhalten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Manueller HF-Install hatte zwei scharfe Kanten:
- kein Fit/OOM-Schutz: zu grosses Modell stuerzte erst beim Laden ab
- stiller Rollen-Diebstahl: exklusiver Alias wanderte kommentarlos weg
Backend: /api/fit leitet params_b jetzt aus KATALOG (echte Metadaten, MoE-bewusst)
oder Namens-Schaetzung ab (params_b<=0) -> Fit-Vorschau fuer beliebige HF-Repos.
Frontend (AddModel): Hardware-Fit-Ampel (perfect/marginal/OOM) mit ~params/req_gb/tps
nach 'Quants laden'; OOM-Gate (zweiter, roter Klick noetig); Warnung welches Modell
die gewaehlte Rolle aktuell haelt und sie verliert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Brain-Kontexte gesenkt (live config): hermes 128K->64K, fast/vision 128K->32K
-> Always-Warm-Footprint 74GB->51GB, ~23GB frei; heavy/coder passen wieder daneben.
- /api/agent/brain liefert jetzt `budget`: projiziert den Always-On-Footprint mit dem
empfohlenen Brain gegen das GTT-Budget (aus amdgpu.gttsize) und prueft, ob das groesste
on-demand-Modell daneben passt (fit.estimate_memory_gb).
- Cockpit Agent-Hirn-Karte: Budget-Zeile (gruen/rot) + Warnung im Update-Confirm, wenn ein
zu grosses Always-On-Brain das groesste on-demand-Modell verdraengen wuerde. Button wird rot.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>