Initial: Mesh-Skills, Configs, Scripts

This commit is contained in:
root
2026-09-02 23:49:07 +02:00
commit 26c7980750
783 changed files with 145393 additions and 0 deletions
@@ -0,0 +1,48 @@
# Hermes-System-Operation (VPS/Master) — durable Regeln für Config-/Budget-Management
> Session 2026-08-08: Nutzer legte fest, wie der Master sein eigenes System verwaltet.
> Diese Regeln sind klasse-weit gültig und ausdrucklich gewollt — NIE ignorieren.
## 1. Hermes-Config NIE via patch/editor ändern — IMMER `hermes config set`
`patch`/`write_file` auf `/root/.hermes/config.yaml` wird abgelehnt („Refusing to write to Hermes config file"). Der Weg ist ausschließlich:
```bash
hermes config set <pfad.zum.key> <wert> # z.B. approvals.mode auto
hermes config get <pfad.zum.key> # rücklesen/verifizieren
```
Beispiel (NUTZER-TROTZ): die falsche Schlüsselnotiz `models.` → richtige `model.` (Singular) bei OpenRouter; beide werden von `hermes config set` geschrieben, aber nur der echte Key wirkt.
## 2. approvals.mode = auto (NUTZERFREIGABE 2026-08-08)
- `hermes config set approvals.mode auto` — reduziert „allow?"-Rückfragen bei normaler Systemarbeit.
- **Sicherheitsnetz bleibt:** die `command_allowlist` (recursive delete, overwrite system config, sudo-Eskalation, …) ist eine **harte Sperre** und greift auch in auto — die kann kein Agent freigeben, bewusst.
- `mcp_reload_confirm` + `destructive_slash_confirm`: **bleiben aktiv** (Nutzer: „Auch ok" — als Schutz behalten).
## 3. BACKUP-ONLY-REGEL (NUTZER, nicht verhandelbar)
> „Wenn also Backup und Rückkehr Optionen da sind, brauchen wir kein extra allow."
Vor **JEDER** System-/Config-/Skript-Änderung zuerst ein Backup + Rückkehr-Option anlegen:
```bash
cp <datei> <datei>.bak-$(date +%s)
```
- Vor systemd-Unit-Änderung → aktuelle Unit-Datei sichern.
- Vor Firewall/UFW → Regelstand exportieren.
- Solange ein Rollback existiert, ist keine weitere Freigabe nötig.
- Hermes legt bei `hermes config set` selbst `.bak.*`-Dateien an — zusätzliche `.bak` bei eigenen Skripten trotzdem setzen.
## 4. Memory-Limits (konfigurierbar, verdoppelt 2026-08-08)
Der Nutzer wählte „Memory verdoppeln" statt bestehende Einträge zu streichen (beides per `hermes config set`):
- `memory.memory_char_limit`: **4400** (war 2200)
- `memory.user_char_limit`: **2750** (war 1375)
Vorher „Memory voll"-Fehler: NICHT bestehende Einträge löschen, sondern Limit erhöhen (Nutzerpräferenz) und/oder kurz verdichten.
## 5. „Wir, nicht du" — Team-Pflicht (Nutzer-Frust aus 2026-08-08)
Der Nutzer korrigierte mehrfach: Master soll bei den Kernsystemen NICHT allein bauen, sondern **Team einspannen** (Brainstorming + gegenseitiges Code-Review), auch wenn das mehr Tokens kostet (4 günstige Agents > 1 teurer Agent). Merke: Der Funktions-Review (z.B. Monats-Delta-Logik der Bremse) wurde von Unraid/Switch echte Fehler finden lassen (row[0]-Basis-Wahl fehleranfällig → Vormonats-Basis-Fix). Allein hätte der Master diese Lücken evtl. nicht gesehen. PITFALL: „Es war Solo schneller" ist keine Ausrede — die Team-Gegenprüfung ist der vereinbarte Standard.
@@ -0,0 +1,61 @@
# PersoEnt APK Build — Session-Transcript (2026-08-07)
Voller Verlauf des ersten Flutter-APK-Builds auf dem Headless-VPS (netcup, Ubuntu 24.04). Konkrete Fehlerbilder + Versionen, die beim Wiederholen helfen.
## Versionen (funktionierender Stack)
- Flutter 3.24.5 stable · Dart 3.5.4
- Java: OpenJDK 17.0.19
- Android SDK: platforms;android-34, build-tools;34.0.0 (+ auto-nachgeladen 33.0.1)
- AGP 8.1.0 (im Projekt `android/settings.gradle`), Kotlin 1.8.22
## Fehlerbilder & Fixes
### 1. "The current Flutter SDK version is 0.0.0-unknown" beim pub get
```
fatal: detected dubious ownership in repository at '/opt/flutter'
Because persoent_app depends on health_connect any which requires Flutter SDK version >=2.5.0, version solving failed.
```
Ursache: `/opt/flutter` einem anderen Eigentümer (root beim Entpacken) als git-owner erwartet → Flutters git-Versionserkennung bricht. NICHT das health_connect-Paket, das war Red Herring.
Fix: `git config --global --add safe.directory /opt/flutter`. Danach `flutter --version` → `3.24.5 • stable • https://github.com/flutter/flutter.git`.
### 2. `flutter pub add health_connect` half nicht, bis safe.directory gesetzt war
Erst safe.directory, DANN wiederholte `pub add` erfolgreich. Reihenfolge zählt: ohne Versionserkennung kann pub nicht lösen.
### 3. AGP 8.1 `namespace`-Konflikt (health_connect entfernt)
```
FAILURE: A problem occurred configuring project ':health_connect'.
> Could not create an instance of type ... LibraryVariantBuilderImpl.
> Namespace not specified. Specify a namespace in the module's build file.
```
AGP 8.1 erzwingt `namespace` in jedem Modul; älteres `health_connect`-Plugin (version ^0.0.0) hat keins. Fix: `flutter pub remove health_connect` und Grund-APK (ohne natives Health-Plugin) bauen. Health-Integration separat lösen (z.B. AGP-Angleich oder anderes Plugin).
### 4. `test/widget_test.dart` Default bricht analyze
Default-Test referenziert `MyApp` (alte Template-Klasse). Nach App-Umbau: Test auf echten App-Widget-Namen updaten (hier `PersoEntApp`, `expect(find.text('PersoEnt'), findsWidgets)`).
## Build-Befehle
```bash
export PATH="$PATH:/opt/flutter/bin"
export ANDROID_HOME=/opt/android-sdk
cd /opt/persoent_app
flutter analyze # sauber machen
flutter build apk --release # erstmal lang (Gradle-Downloads); ~2min danach
# Ergebnis: build/app/outputs/flutter-apk/app-release.apk (22.2MB)
```
## Deploy zum Download
```bash
mkdir -p /var/www/persoent.perfekt-ohne-en.de/html/app
cp build/app/outputs/flutter-apk/app-release.apk /var/www/persoent.perfekt-ohne-en.de/html/app/PersoEnt-Android.apk
chown -R www-data:www-data /var/www/persoent.perfekt-ohne-en.de/html/app/
# Zugriff: https://persoent.perfekt-ohne-en.de/app/PersoEnt-Android.apk → HTTP 200
```
## PocketBase aus App heraus (CORS/Vorbereitung)
- App nutzt `PocketBase('https://persoent.perfekt-ohne-en.de/pb')` (nginx `/pb/` → 127.0.0.1:8090)
- **Offen (noch nicht gelöst):** CORS für den mobilen Client muss in PocketBase freigegeben werden, sonst schlägt `authWithPassword` aus der App fehl. `test/widget_test.dart` vorhanden — nur Grundgerüst ohne Health-Connect.
## Status
- ✅ Login-Screen (E-Mail/Passwort via PocketBase) + Dashboard-UI (Schritte/Puls/Schlaf/Gewicht-Platzhalter)
- ⏳ Health-Connect-Plugin + echtem Datenabgleich: noch offen (AGP-Konflikt)
- ⏳ Google-Sign-In: Dependencies vorhanden, Flow noch nicht verdrahtet
- ⏳ PocketBase-CORS für App-Client
@@ -0,0 +1,149 @@
# PersoEnt-Kosten-Tracking + Budget-Bremse (OpenRouter) — Verlauf & Referenzwerte
> Session 2026-08-07: Nutzer wollte Kostenübersicht für Statistik + künftige Mesh-Bremse. Es wurde festgestellt, dass **keine Kosten im Ereignis-Log erfasst** waren (zeigt 0€), obwohl OpenRouter Budget verbraucht war. Danach wurde das komplette **Bremse-System gebaut und E2E-getestet**.
## Das gebaute System (Master/VPS)
| Komponente | Pfad | Zweck |
|---|---|---|
| `mesh-cost-track.sh` | `/usr/local/bin/` | Stündlich OpenRouter-Usage aller 4 Agenten (VPS+3 Sub) via API abfragen, in Zeitreihe schreiben |
| Zeitreihe | `/srv/work/costs/costs.jsonl` | wachsende Statistik je Agent (ts, master, unraid, switch, laptop) |
| `mesh-cost-report.sh` | `/usr/local/bin/` | erzeugt HTML-Kosten-Übersicht (Dashboard-USD + pro-Agent + Bremse-Status) |
| `budget.yaml` | `/srv/work/costs/` | Deckel: `limits.agent.*`, `limits.gesamt_pro_tag`, `modelle.erlaubt/blockiert`, `bremse.kill_switch_file` |
| `mesh-cost-break.py` | `/usr/local/bin/` | vergleicht Tages-Usage vs. budgurations → schreibt `kill_switches.json` |
| `kill_switches.json` | `/srv/work/costs/` | zentral, **chmod 0666** — welcher Agent PAUSED |
| Agent-Poller-Guard | in `mesh-agent-poller.sh` | liest kill_switches per SSH; bei PAUSED → keine Task-Bearbeitung |
| Cron (stündlich) | `0 * * * *` | `mesh-cost-track.sh && python3 mesh-cost-break.py` |
| Doku-Integration | master-report.sh | `$(bash /usr/local/bin/mesh-cost-report.sh)` vor Betriebsregeln |
## 🔥 PITFALL 1: OpenRouter-Usage-Einheit ≠ Dollar
- `GET https://openrouter.ai/api/v1/auth/key` mit `Authorization: Bearer <KEY>` → `data.usage` = **OpenRouter-Credits je Key**.
- Für die Agenten (je eigener Key in `~/.hermes/.env`) ergeben sich z.B.: master 39.5, unraid 0.33, switch 0.64, laptop 0.87.
- **Summiert (≈41) DIFFERIERT vom OpenRouter-Dashboard ($20.51)** — die API-Credits sind nicht 1:1 USD, und es können verschiedene Key-Pools/Konten sein.
- **Verbindlicher Maßstab ist der Dashboard-USD-Wert** (Nutzer liest ihn in der OpenRouter-UI ab). Den als `nutzer_dashboard_usd` mit Quelle in die Zeitreihe schreiben.
## 🔥 PITFALL 2: Usage ist KUMULATIV — Tages-Delta berechnen
Ohne Korrektur wäre **jeder Agent dauerhaft PAUSED**, weil die kumulierte Gesamt-Usage (seit Key-Start) jeden Deckel sprengt. Fix im Brems-Skript: **Tages-Delta = letzter Wert minus erster Wert desselben Kalendertags**:
```python
today = last["ts"][:10]
today_rows = [r for r in rows if r["ts"][:10] == today]
first = today_rows[0] if today_rows else last
delta = max(0.0, float(last[agent]) - float(first[agent]))
```
## Bremsen (GEBAUT + E2E-getestet 2026-08-07)
Nutzerwunsch: Master überschaut Kosten pro+gesamt über ein wachsendes Mesh (mehr Agents, mehrere Server) und kann alles bremsen. Umsetzung:
1. `mesh-cost-break.py` liest letzte Usage-Zeile (Tages-Delta), vergleicht mit `budget.yaml`-Deckeln.
2. Bei Deckel-Überschreitung (je Agent ODER Gesamt) schreibt es `kill_switches.json` mit `PAUSED`-Status + Grund.
3. Jeder Sub-Agent hat im `mesh-agent-poller.sh` einen **Guard** am Anfang (vor Task-pull), der per SSH prüft: "bin ich PAUSED?" → wenn ja: `exit 0` (keine Task-Übernahme, keine weiteren Kosten).
```bash
# Guard in mesh-agent-poller.sh (nach SSH_CMD, vor Task-pull)
KILL_CHECK=$($SSH_CMD "python3 -c \"
import json
try: d=json.load(open('/srv/work/costs/kill_switches.json'))
except Exception: d={}
sw=d.get('kill_switches',{}).get('<MEINE_ID>',{})
print('PAUSED' if sw and sw.get('status')=='PAUSED' else 'OK')
\" 2>/dev/null")
if [ "$KILL_CHECK" = "PAUSED" ]; then log "⏸️ Budget-BREMSE aktiv"; exit 0; fi
```
**E2E-Test:** UnraidHermes auf PAUSED gesetzt → sein Task blieb in `offen/` (Bremse griff), Poller-Log zeigt "⏸️ Budget-BREMSE aktiv ... pausiert". Nach Reset (leere kill_switches) wieder normal. Der aktualisierte Poller-Guard muss an alle 3 Sub-Agenten verteilt werden (je passender Key-Pfad: `unraid_mesh`/`switch_mesh`/`laptop_mesh`).
## Kostenfakt (OpenRouter-Analyse 07.08, 1 Monat)
- **DeepSeek V4 Pro = 64% aller Kosten (~$26.80)** — teures Top-Modell, nicht Standard lt. Model-Allocation; der Haupt-Kostentreiber.
- Andere: V4 Flash 0731 22,5%, V3 5,9%, Nemotron 2,4%, GLM 1,5%.
- **→ Bremsen muss auf Modell-Ebene ansetzen** (teure Modelle blockieren/deckeln), nicht nur auf Agent-Tages-Summe. Aktuell `modelle.blockiert` in budget.yaml als Konfig/Log; harter Blocker (Modell gar nicht erst laden) ist offen.
## Abfrage-Snippets
### Master (lokal)
```bash
python3 << 'PYEOF'
import json,re,urllib.request
e=open('/root/.hermes/.env').read()
m=re.search(r'OPENROUTER_API_KEY=([A-Za-z0-9_\-\\.]+)',e)
req=urllib.request.Request("https://openrouter.ai/api/v1/auth/key",
headers={"Authorization":f"Bearer {m.group(1)}"})
print(json.load(urllib.request.urlopen(req,timeout=15))["data"]["usage"])
PYEOF
```
### Sub-Agent per SSH (Key bleibt lokal, nur Zahl kommt zurück)
```bash
u=$(sshpass -p 'Bp3lskt0' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=12 mehlzoerwer@<IP> '
python3 -c "
import json,re,urllib.request
e=open(\"/home/mehlzoerwer/.hermes/.env\").read()
m=re.search(r\"OPENROUTER_API_KEY=([A-Za-z0-9_.\-]+)\", e)
req=urllib.request.Request(\"https://openrouter.ai/api/v1/auth/key\", headers={\"Authorization\":\"Bearer \"+m.group(1)})
print(json.load(urllib.request.urlopen(req, timeout=15))[\"data\"].get(\"usage\",0))
"')
```
## Erweiterungen/POLISH 2026-08-08 (Team-geprüft: Unraid+Switch+Laptop)
Das System wurde im Team geschliffen (Gegenprüfung fand echte Fehler). Ergänzungen:
### 🔥 PITFALL 3: Es gibt DREI OpenRouter-Kostenquellen — verwechsle sie nicht
| Endpoint | Feld | Einheit | Zweck |
|---|---|---|---|
| `GET /api/v1/auth/key` | `usage` | OpenRouter-Credits (je Key) | pro-Key-Verteilung, **grobe Relation nur** |
| `GET /api/v1/credits` | `total_usage` | **USD, konto-weit** | **VERBINDLICH fürs Gesamtbudget** |
| `POST chat/completions` | `usage.cost` | USD (im Body) | Kosten je Antwort (Header `X-OR-Usage-Cost-USD` oft NICHT da — Body bevorzugen) |
**Merke:** `/auth/key usage` ≠ USD und summiert anders als `/credits`. Beispiel: `/auth/key`-Werte (41.3) vs `/credits total_usage` (81.45 USD) vs Dashboard ($20.51) — drei verschiedene Zahlen. Für Gesamt-Deckel IMMER `/api/v1/credits` `total_usage` (USD) nehmen; pro-Key-`usage` nur als Aktivitäts-Relation.
### Tages-Delta KORRIGIERT (tag-übergreifend statt innerhalb des Tages)
Der naiv "letzter minus erster Wert des Kalendertags" hat Lücken: Mitternachts-Lücke zwischen Tag N und N+1, Ein-Eintrag-Tag → 0, Counter-Reset → negatives Delta (falsche "Ersparnis"). **Korrekt:**
```python
# Delta für Tag = letzter Wert heute − letzter Wert VORTAG; max(0,…) gegen Reset
vorher = [d for d in daten if d < heute]
base = tvals[vorher[-1]] if vorher else cur
delta = max(0.0, cur - base)
```
Zusätzlich: **7-Tage-Kumulativ-Summe** (fängt "täglich unter Deckel, aber Monat explodiert") + **80%-Warnschwelle** vor hartem PAUSED.
### Master-exempt (Design-Entscheidung)
Der **Master (VPSHermes) wird NIE hart pausiert** — er muss sein eigenes System + den Nutzer pflegen. Bei Monats-USD-Cap-Überschreitung werden NUR Sub-Agenten PAUSED. So bleibt das Kun-den-System bedienbar, auch wenn gespart wird.
### Modell hart blockieren (nicht nur Konfig/Log)
Umsetzung des "Bremsen auf Modell-Ebene": Hermes selbst sperrt das Modell, damit es gar nicht erst geladen wird.
```bash
hermes config set model.providers.openrouter.blocked_models '["deepseek/deepseek-v4-pro"]'
```
- **Achtung Singular:** Schlüssel ist `model.providers.…` NICHT `models.` (sonst nur notiert, nicht gelesen).
- Verifikation: Modell taucht in `hermes models list` nicht mehr auf; Fallback greift aufs nächste.
- Allowlist (`allowed_models` nur günstige) ist noch strikter — blockt automatisch neue teure Modelle.
### Referenzwerte 2026-08-08
- `/credits total_usage` (konto-weiter USD-Verbrauch): **$81.53**
- Nutzer-Entscheidung: **strikt sparen** — Monats-Cap auf $80 gesetzt → Sub-Agenten aktuell PAUSED (Master aktiv).
- Nach dem Setzen von Deckeln IMMER `mesh-cost-break.py` nochmal laufen lassen + prüfen, dass Master-exempt korrekt greift (kein Alle-Pausiert-Dauerschleife).
## 🔥 FINALES NUTZER-KOSTEN-MODELL (verbindlich ab 2026-08-08/09) — ersetzt obiges Monats-Cap-Gedächtnis
**Achtung: Der Nutzer hat das Budgetmodell zuletzt klar und EINFACH gemacht. Folge NUR diesem, nicht den komplexen $-Caps oben:**
- **Harte Grenze = 1 USD pro Tag und Agent** (`limits.tageslimit_agent_usd: 1.0`).
- **Solange OpenRouter-Credits (Guthaben) vorhanden sind, wird gearbeitet.**
- **KEIN Team-weiter Monats-Stopp** — nur pro-Agent-Tageslimit + technischer Stopp, wenn das Konto-Guthaben 0 erreicht.
- Auflade-Rhythmus des Nutzers: ~20$ am 1. des Monats, evtl. noch ~20$ am 15. (nicht garantiert). Das ist nur die Auflade-Geschichte, NICHT der Brems-Heebel.
- Master (VPSHermes) bleibt immer aktiv; nur Sub-Agenten werden pausiert.
- `budget.yaml` entsprechend: `tageslimit_agent_usd: 1.0`, `tageslimit_gesamt_usd: 4.0` (4 Agents × 1$), keine `gesamt_usd_monat`-Logik.
- Guthaben-Check im break: `guthaben = total_credits - total_usage`; wenn ≤ 0 → Sub-Agenten pausieren (Master nicht).
**PITFALL Vermeidung:** Nicht wieder ein komplexes „Monats-Cap in $" / Team-Stopp-Schema einführen — der Nutzer hat das aktiv zurückgenommen („Du oder wir?"-Korrekur + „1$ pro Tag und Agent … solange Credits da, kein Monats-Stopp"). Der Fehler aus dem Tag: Tages-Delta/`gesamt_pro_tag`-Key-Bruch und Monats-Cap-Überkomplexität.
## Referenzwerte 2026-08-07 (historisch)
- OpenRouter-Dashboard-Gesamt: **$20.51**
- API-Usage je Agent: master 39.48, unraid 0.33, switch 0.64, laptop 0.87
@@ -0,0 +1,29 @@
# PersoEnt: Google-Gesundheitsdaten-Strategie (2026-08-07)
Fachliche Entscheidung für die PersoEnt-App (Flutter-Android-Prototyp). Verhindert, dass eine künftige Session in die tote Server-REST-Sackgasse läuft.
## 🔑 Kern-Fakt: Es gibt KEINE Server-REST-API mehr für Google-Gesundheitsdaten
- **Google Fit REST API ist deprecated** und wird abgeschaltet — eine Neuentwicklung darauf ist ein totes Pferd.
- **Health Connect** (der Nachfolger) hat **keine öffentliche REST-Schnittstelle für Server-Backend-Sync** — nur die native Android-API (SDK).
- Konsequenz: Echte Google-Gesundheitsdaten (Schritte, Puls, Schlaf, Gewicht) lassen sich serverseitig (VPS) **nicht** per REST-API automatisch pullen.
## Der funktionierende Weg (nativ, zukunftssicher)
PersoEnt muss eine **echte App** sein (nicht Web) → dann nativ:
- **Android:** Health-Connect-SDK direkt in der App → Felder wie `derived:com.google.step_count.delta`, `com.google.weight`, `com.google.heart_rate.bpm`, `com.google.sleep.segment` lesen.
- **iOS (später):** HealthKit (Schritte, Puls, Schlaf, Gewicht).
- Die App synchronisiert mit PocketBase-Backend (VPS, `health_records`).
## Wichtige agile Kompatibilität
- Das pub.dev-Paket **`health_connect` = leer (Version 0.0.0, kein echter Code)** — NICHT nutzbar. Googles offizielle Flutter-Health-Connect-Integration ist ein GitHub-Beispiel, das das Android-SDK nativ bundelt; keine einsatzbereite pub.dev-Bibliothek.
- 2026 gesundet/Weg: natives Android-Health-Connect-SDK im bestehenden Flutter-Projekt (MethodChannel) oder natives Android-Modul. Kein toter publicum REST.
## Die "Detektiv"-Analytik (Produktkern)
Wenn Einträge im `health_records` vorliegen (≥3 pro Nutzer), zeigt die Korrelations-Analyse Zusammenhänge — aber **immer als Korrelation, nie als Kausal-Behauptung** (DSGVO-/Haftungs-sicher; "kein Heil-/Diagnoseversprechen"). PocketBase `sort=-id` (nicht `sort=-created`, das 400 gibt) für "neueste zuerst".
## Test-Zugang PersoEnt (Stand 2026-08-07)
- PocketBase-Superuser + users-Collection; Test-Login `mehlzoerwer@perfekt-ohne-en.de`.
- APK-Build-Mechanik: siehe übergeordneter Skill `mobile-apk-flutter-build`.