Initial: Mesh-Configs vom 03.09.2026 01:23

This commit is contained in:
root
2026-09-03 01:23:55 +02:00
commit 4b65134f8c
797 changed files with 146197 additions and 0 deletions
@@ -0,0 +1,88 @@
# Blueprint-v1 Deployment (02.08.2026) — NFS-Pflicht-Setup & Skripte
Diese Referenz dokumentiert den Übergang auf die Blueprint-v1-Task-Queue
(JSON + offen/in_arbeit/fertig/bugfix/archiv) und die dabei verifizierten
Schritte. Ergänzt die SKILL.md mit dem tatsächlich getesteten Deployment.
## Netzwerk-Einzahl
- **Ein** ZeroTier-Netzwerk: `6ab565387a75e498` (172.24.0.0/16).
Das frühere Netz `b9a18a606fb05ae6` (10.36.223.x) ist **gelöscht**.
- Agenten: A=172.24.196.119 (Master/Hub), B=172.24.34.142,
SwitchHermes=172.24.20.26, LaptopHermes=172.24.178.202 (oft offline).
Handy = kein Agent.
## NFS als Pflicht-Dateisystem (verifiziert)
Ein Task, der "Sub-Agenten selbst im Share schauen lässt" statt manuellem
Auffordern, erfordert einen gemeinsam sichtbaren Ordner. **NFS ist Pflicht**;
Samba/CIFS wird abgelehnt (Onboarding blockiert). Zwei Stolpersteine beim
Einrichten:
1. **UFW blockt NFS stumm.** Symptom: `ping` zum Export-Host geht, aber
`mount -t nfs …` hängt/fails und auch der Porttest
`timeout 5 bash -c "echo >/dev/tcp/172.24.196.119/2049"` schlägt fehl.
Fix (nur aufs ZT-Subnetz):
```
ufw allow from 172.24.0.0/16 to any port 2049 proto tcp # nfs
ufw allow from 172.24.0.0/16 to any port 111 proto tcp # rpcbind
ufw allow from 172.24.0.0/16 to any port 111 proto udp
ufw allow from 172.24.0.0/16 to any port 20048 proto tcp # nfs lockd
```
Danach `exportfs -ra && systemctl restart nfs-kernel-server rpcbind`.
2. **requiretty/sudo auf Sub-Agenten (Zorin/PopOS).** `sudo` per SSH über
stdin schlägt fehl ("ein Terminal ist erforderlich"). Lösung — Askpass:
```bash
echo '#!/bin/bash' > /tmp/ap.sh && echo "echo <PW>" >> /tmp/ap.sh && chmod +x /tmp/ap.sh
export SUDO_ASKPASS=/tmp/ap.sh
sudo -A <befehl>
```
3. **NFS-Export nur aufs ZT-Subnetz** statt `*`:
```
/srv/work/tasks 172.24.0.0/16(rw,sync,no_subtree_check,no_root_squash)
```
## Master-Skripte (auf dem Hub/VPS, /usr/local/bin/)
| Skript | Zweck |
|--------|-------|
| `duo-task-create.sh <ziel> <typ> <prio> <beschreibung>` | legt JSON-Task in `tasks/offen/` ab |
| `duo-master-poller.sh` | Ausfall-Fallback: Task >30s in `offen/` → `ziel_agent="beliebig"` (Original bleibt in `original_ziel_agent`) |
| `duo-master-report.sh` | generiert `dokumentationen.perfekt-ohne-en.de/index.html` live aus den Task-Ordnern |
| `duo-agent-poller.sh <meine-ip> <meine-id>` | Sub-Agent-Poller: 10s-Takt, atomarer `mv`-Lock nach `in_arbeit/` mit Präfix C.D_ |
### Master-Crontab (versetzt)
```
* * * * * /usr/local/bin/duo-master-poller.sh >> /var/log/mesh-poller.log 2>&1
* * * * * sleep 30; /usr/local/bin/duo-master-poller.sh >> /var/log/mesh-poller.log 2>&1
* * * * * sleep 30; /usr/local/bin/duo-master-report.sh >> /var/log/mesh-doku.log 2>&1
```
### Ausfall-Fallback (getestet)
Der Poller wurde mit künstlich auf 45s gealtertem Task verifiziert:
`ziel_agent` → `"beliebig"`, `original_ziel_agent` bleibt `"LaptopHermes"`.
Atomarer `mv`-Rename in `duo-agent-poller.sh` entscheidet bei Konkurrenz:
erster Erfolg gewinnt, zweiter scheitert und bricht still ab.
## Credential-Audit (Wichtig fürs nächste Mal)
- SSH-Zugangsdaten liegen **im Klartext im Skill** `multi-agent-mesh`
(SSH-User/Passwort in Befehlen), NICHT in `.env` und es gibt keine SSH-Keys
(`authorized_keys` leer). Rollen-Informationen stehen in `/srv/work/registry.json`.
- Empfehlung (nicht eigenmächtig): Migration zu `age`/`gpg`-Vault + SSH-Public-Key.
Wenn der Skill geteilt/gesynct wird, sind Klartext-PWs ein Leak-Risiko.
## Task-Dateiformat (Blueprint v1)
Felder: `task_id, ziel_agent, aufgabentyp, prioritaet, budget_limit_eur,
status, ergebnis_pfad, original_ziel_agent` + z.B. `beschreibung, anlage_ts,
in_arbeit_ts, fertig_ts`. Status = Ordnerzugehörigkeit, nicht nur das Feld.
## Doku-Website
- Domain: `dokumentationen.perfekt-ohne-en.de` (Nginx vhost + Let's Encrypt
via `certbot --nginx -d …`). Stellt die Live-Übersicht aller Tasks aus dem
Share dar; Agenten-Tabelle mit Status (online/offline).
- Kein PHP nötig — statisches HTML wird durch `duo-master-report.sh` regeneriert.
@@ -0,0 +1,55 @@
# Dokumentations- & Archiv-Subsystem (2026-08-03, validiert)
Nutzer-Präferenz abs. Priorität: **ALLES wird automatisch dokumentiert und
jederzeit sichtbar** („Das will ich immer sehen können"). Doku ist kein
nachgelagerter Text, sondern ein live generiertes Panel + chronologisches Archiv.
## Komponenten
| Komponente | Ort | Funktion |
|------------|-----|----------|
| Ereignis-Log | `/srv/work/log/events.jsonl` | Jede Aktion, JSONL append |
| Live-Panel | `Dokumentationen.perfekt-ohne-en.de` | Echtzeit-Übersicht (Tasks, Agenten, Kosten, Log) |
| Tages-Archiv | `Archiv.perfekt-ohne-en.de` | Pro-Tag-Zusammenfassung, chronologisch |
## Skripte
- `/usr/local/bin/mesh-log.sh <aktion> <detail> [agent] [kosten_eur]` —
appendet Zeile an `events.jsonl`. Immer bei jeder Aktion aufrufen!
```json
{"ts":"<ISO>","aktion":"...","agent":"agent-a","kosten_eur":0.000,"detail":"..."}
```
- `/usr/local/bin/duo-master-report.sh` — regeneriert das Live-Panel aus
`/srv/work/tasks` **und** `/srv/work/log/events.jsonl` (letzte 40 Events,
heutige Kosten = summiert aus events.jsonl). Cron: `* * * * * sleep 30`.
- `/usr/local/bin/duo-daily-archive.sh` — erzeugt `Archiv.perfekt-ohne-en.de/<datum>.html`
mit Tages-Stats (Aktionen, Kosten, fertig/offen/bugfix) + Ereignisliste.
Schreibt außerdem `index.html` als chronologische Linkliste.
Cron: `50 23 * * *` (täglich 23:50).
## Pitfalls (real getestet)
- **`ls /path/*.json` unter `set -euo pipefail` bricht mit Exit 2 ab**, wenn der
Glob leer ist (kein Match). Fix: `shopt -s nullglob` vor den Zähl-Loops
einsetzen (gilt für `duo-master-report.sh` UND `duo-daily-archive.sh`).
- **Website-Verifikation:** `curl -s -o /dev/null -w "%{http_code}" <url>` nach
jeder Generierung. Standard-Docroot existiert, aber der generierte Inhalt
fehlt erst → `403/404` = Skript brach ab, nicht die Website.
- **Grid/Liste leeres Verzeichnis:** `grep -v index.html` auf leeren Glob
ebenfalls mit `nullglob` schützen, sonst Exit 2.
## Einrichtung (Subdomain)
```bash
mkdir -p /var/www/Archiv.perfekt-ohne-en.de
# nginx vhost (listen 80 → root), ln -sf ins sites-enabled, nginx -t && reload
certbot --nginx -d Archiv.perfekt-ohne-en.de --redirect --agree-tos -m admin@perfekt-ohne-en.de
```
Big-Real-Fix: Die Subdomain erreicht per DNS denselben Server (92.60.38.175),
eigenes cert + eigener vhost pro Site.
## Budget
Kosten werden pro Ereignis in `events.jsonl` geloggt und pro Tag summiert
(Live-Panel zeigt „Heutige Kosten"). Budget-Regel: 1 €/Agent/Tag, kein
sprunghafter Modellwechsel ohne expliziten Nutzerwunsch.
@@ -0,0 +1,72 @@
# Failover-Poller Reaktivierung + Update-Cadence (2026-08-06)
## Ausgangslage
- Am **2026-08-03** wurde `mesh-master-poller.sh` deaktiviert (Flag `AUSFALL_FALLBACK_AKTIV=0`),
weil das **30s-Fenster zu aggressiv** war: `VERPASST=30` < 1 Polling-Zyklus (30–60s), wodurch
jeder frische Task (HelloWorld, Wissensbasis) fälschlich auf `ziel_agent='beliebig'` umgeleitet wurde.
- Am **2026-08-06** (Nutzer zufrieden mit Systemzustand) wieder aktiviert — aber **robust** statt aggressiv.
## Nutzer-Grundregel (WICHTIG)
> „zeiten erfragen noch mit problemlöser vorher!!!" — **bevor Betriebs-Zeitparameter (Failover-Fenster,
> Polling-Intervalle) gesetzt werden, IMMER den Problemlöser konsultieren**, nicht eigenmächtig raten.
> Ablauf: `mesh-task-create.sh UnraidHermes "<auftrag>" brainstorming high 0.5 "<Briefing + JSON-Frage>"`
> an einen online-rechenstarken Agenten (UnraidHermes), Ergebnis-JSON validieren, DANN umsetzen.
> Der 03.08.-Fehler kam genau von Setzen ohne Abstimmung.
## Vom Problemlöser (UnraidHermes) empfohlene Parameter
```json
{
"verpasst_sekunden": 180,
"modus": "nur_alarm",
"ping_check": true,
"begruendung": "180s = 3 volle Polling-Zyklen bei 30-60s Cron-Intervall. Nur-Alarm statt auto_relabel verhindert Fehlumlackierung wie am 03.08. Ping-Check: Alarm feuert nur wenn Ziel-Agent wirklich down, nicht bei Latenz/Auslastung."
}
```
Begründung:
- **180s statt 30s:** 30s war < 1 Zyklus → jeder frische Task sofort "verwaist". 60s = 1 Zyklus (zu knapp,
kein Cron-Jitter-Puffer). 180s = 3 Zyklen → ein online Agent hat 3 Chancen den Task zu sehen; ein
beschäftigter Agent wird nicht fälschlich als weg erkannt.
- **Ping-Check:** `ping -c1 -W2 <zt-ip>` vor Alarm; nur wenn Ziel wirklich down → Alarm. Verifiziert
2026-08-06: frischer Task = still, alter Task + online Agent = still (kein Fehlalarm). Laptop war
wieder online → korrekt kein Alarm.
- **Modus `nur_alarm`:** schreibt nur `AUSFALL_ALARM` ins Event-Log `/srv/work/log/events.jsonl`,
Master entscheidet manuell. Kein Auto-Relabel (die Wurzel des 03.08.-Bugs). Späteres Upgrade auf
`auto_relabel` NUR nach nachgewiesener Ping-Erkennungs-Stabilität.
## Umsetzung in mesh-master-poller.sh
- `AUSFALL_FALLBACK_AKTIV=1`
- `VERPASST=180`
- Schleife über `offen/*.json`: Alter = `now - anlage_ts`; wenn `>180s` → Agent-IP aus Registry auflösen,
Ping-Check; wenn online → `continue` (kein Alarm); wenn down → Event-Log-Eintrag (`AUSFALL_ALARM`).
- Cron: `* * * * * /usr/local/bin/mesh-master-poller.sh >> /var/log/mesh-poller.log 2>&1` (alle 60s).
- Kein Auto-Relabel, kein `beliebig`.
## Update-Cadence (Nutzer-Entscheid 2026-08-06)
Brainstorming über Rhythmus (Technik/KI-Experte/Nerd/Kaufmann) ergab: **wöchentlich** statt täglich.
| | täglich | alle 3 Tage | **wöchentlich** |
|---|---|---|---|
| Risiko | klein, oft | mittel | kumuliert, 1× gebündelt |
| Aufwand | 28×/Monat | 10×/Monat | **4×/Monat** |
| Mesh-Sync | ständig driftend | ok | 1× sauber synchron |
Politik:
- **Sicherheits-Hotfixes** (SSH, Auth, Keys, ZeroTier) → **sofort**, nicht warten.
- **Feature-/Routine-Updates** → wöchentlich gebündelt; alle 4 Agenten in einem Zug + 1× Verifikation.
- Changelog vor dem Durchziehen kurz auf Breaking-Changes prüfen.
- Umsetzung: Cron-Job `mesh-hermes-wochenupdate` (Mo 06:00, deliver=telegram, no_agent) ruft
`/root/.hermes/scripts/update_mesh.sh` — updatet Master + UnraidHermes .34.142 + SwitchHermes .20.26 +
LaptopHermes .178.202 synchron (`hermes update --yes` via SSH + sshpass), verifiziert Versionen.
Stille bei "kein Update nötig"; Meldung nur wenn es was zu tun gibt/Problem.
## Verifikations-Hinweis
- Der Alarm-Zweig (echte Down-IP) konnte an dem Tag live nicht mehr getestet werden (alle Agenten online;
destruktiver Test wurde angehalten). Kern-Verhalten (frisch=still, alt+online=still) verifiziert; der
Down-Pfad ist trivialer Code, aber als "validiert" erst nach einem echten Ausfall anzusehen.
@@ -0,0 +1,87 @@
# Mesh File-Based Task Queue — Detail (Stand 2026-08-02)
Entstanden aus Nutzer-Frust über leere Webhook-Antworten und Agenten, die
Aufgaben versprechen aber nie Rückmeldung geben. Nutzer-Präferenz: Agents
sollen sich über den Share DIREKT verständigen, OHNE manuellen Relay. Der
Nutzer mischt sich nur bei kostenpflichtigen Aktionen ein (Essen bestellen,
Token-Kauf).
## Warum File-basiert statt Webhook
- Webhooks A→B liefern 202, aber B antwortet ins Leere (void); Nutzer musste
Relay spielen.
- Hermes blockt curl/Shell aus Webhook-Sessions (Sandbox).
- Rollback-Pfade unfair: Webhook = einseitig, keine Lebenszeichen.
- File-Status über Ordner ist atomar, idempotent, konfliktfrei per `mv`.
## Ordnerstruktur
```
/srv/work/
├── todo/ # offene Aufgaben (Dateiname = <ZT-IP>_<name>.md)
├── inProgress/ # wird bearbeitet
├── finished/ # erledigt, verifiziert
├── bugged/ # gescheitert / Formatfehler
└── completed/ # fertige Artefakte (HTML, Dateien, ...)
```
## Task-Dateiformat (YAML Frontmatter + Markdown)
```markdown
---
task_id: hello-world-001
assigned_to: 172.24.34.142 # Ziel-Agent-ZT-IP (Dateiname = Präfix)
created_by: agent-a
project: Mesh-Test
retries: 3
status: todo
---
# Titel
Aufgabenbeschreibung. Ergebnis schreibt der Executor unter `# Ergebnis`.
```
## Executor-Regeln (Sub-Agent)
1. Nur Dateien greifen, deren Dateiname die EIGENE ZT-IP trägt
2. `todo/` → `inProgress/`
3. Ergebnis unter `# Ergebnis` in dieselbe Datei
4. `inProgress/` → `finished/` (Erfolg) oder → `bugged/` (eigener Fehler)
## Master-Cron (`scripts/master-task-handler.sh`)
- Cron: `*/5 * * * *`
- Bereinigt verwaiste `.lock` (>15 min)
- Stale inProgress-Dateien (>30 min, ohne Lock) → zurück nach todo
- finished/ validiert: YAML-Frontmatter + `# Ergebnis` vorhanden
- bugged/: `retries > 0` → dekrementieren + zurück nach todo; sonst bleibt
- Artefakte nach completed/ spiegeln (optional auch auf Dokumentations-Website)
## Share-Sicherheit (nur ZeroTier, nie öffentlich)
Samba:
```ini
[work]
path = /srv/work
hosts allow = 172.24. # ZeroTier-Subnetz
hosts deny = 0.0.0.0/0
```
NFS: `/srv/work <ZT_IP>(rw,sync,no_subtree_check)` in /etc/exports
SSHFS: `sshfs root@<ZT_IP_A>:/srv/work /srv/work`
## Pitfalls
- Aufgabe in `todo/` legen reicht NICHT ohne Executor-Cron auf der Gegenseite
→ bleibt ewig liegen (wie Message Bus ohne Poll-Cron).
- Verwaistes Ergebnis-Slot: Webseite zeigt Aufgabenliste live aus Share;
Render-Pfad `/completed/` immer anlegen.
- Netzwerk konsolidieren: nur EIN aktives ZT-Netzwerk. Nach Wechsel Samba/NFS-
Regeln, UFW, Skills, duo_state.json auf neue Subnetze prüfen.
- Nutzer-Präferenz „kein Ghosting": versprochene Aktion AUSFÜHREN und Ergebnis
melden — nie nur „ich mache es" schreiben und verstummen.
## Beispiel-Projektsync
Eine Dokumentations-Website (z.B. dokumentationen.perfekt-ohne-en.de) zeigt
alle Tasks und ihre Status live aus dem Share; Hello-World-Test als erstes
Mesh-Artefakt.
@@ -0,0 +1,28 @@
# PersoEnt: Google Health-Daten-Anbindung — Entscheidung (2026-08-07)
## Verhindert Wiederholung
Nur damit starten zu wollen "Google Health Connect per REST abgiechen" ist ein **totes Pferd** — die nächste Session würde sonst denselben toten Weg vorschlagen.
## Autoreitative Fakten (verifiziert 2026-08-07, Rechen-Agent SwitchHermes + Master)
1. **Google Fit REST API ist DEPRECATED** und wird abgeschaltet. Eine Neuentwicklung darauf ist nicht zukunftssicher.
2. **Google Health Connect** (der Android-Nachfolger) hat **KEINE Server-/REST-Schnittstelle** — nur die Android-App-Erweiterung (SDK auf dem Gerät). Kein serverseitiger Datenpull wie bei alter REST-API.
3. Apple-Pendant: **HealthKit** (iOS, nativ).
## Konsequenz für die Architektur
Um deine (Nutzer-)echten Google-Gesundheitsdaten automatisch zu bekommen, muss PersoEnt **eine native App** sein, nicht nur eine Website:
- **Android:** Health-Connect-SDK nativ in der App → Daten vom Handy lesen
- **iOS:** HealthKit nativ
- App synchronisiert zu unserem **PocketBase**-Backend (VPS) über REST.
## Entscheidung (Nutzerwunsch, 08-07)
**Zuerst ein Android-Prototyp (APK), iOS später.** Nutzer testet APK auf seinem Handy.
## Baustraße / Toolchain-Status
- VPS (Master): Flutter ❌, Java ❌, Android-SDK ❌, adb ❌ — aber reichlich Ressourcen (15 GB RAM, 278 GB frei).
- LaptopHermes (172.24.178.202, RTX 2060): ebenfalls keine Flutter/Java-Toolchain.
- VPS ist headless → APK-Build möglich (Gradle/Build-Tools), aber KEIN Android-Emulator zum In-Test; Nutzer testet die APK direkt am Handy.
- Option A: Flutter auf dem VPS aufsetzen (Master-kontrolliert, DSGVO-sauber, alles unter uns). Option B: auf LaptopHermes bauen.
- Backend + PocketBase laufen bereits (persoent.perfekt-ohne-en.de); das bleibt.
## Nächster Schritt (unentschieden zum Stand des Sessions-Ende)
Baustraße wählen (A: VPS vs B: LaptopHermes), Flutter-SDK + Android-SDK + Gradle installieren, leeren APK-Prototyp bauen, Health-Connect-SDK + PocketBase-Sync danach.
@@ -0,0 +1,91 @@
# SSH Direct Review Protocol (A+B-Methode, 01.09.2026)
## Problem
Sub-Agenten sehen `/srv/work/tasks/` NICHT im NFS-Share. Sie haben keinen Zugriff auf
Master-Dateien. URLs allein reichen nicht (`curl -s https://domain/` liefert leer oder
scheitert am Tool-Limit). Datei-basierte Reviews mit 5 Prüfpunkten pro Task führen
dazu, dass Sub-Agenten am Iterations-Limit scheitern.
## Lösung: A+B Methode
**A = Task kleiner schneiden** (1 Prüfpunkt statt 5 pro Task)
**B = Inhalt per SSH direkt schicken** (scp + hermes chat --oneshot statt Datei-Queue)
## Workflow
```mermaid
sequenceDiagram
Master->>Master: Schreibe Einzel-Punkt-Prompt in /tmp/prompt.txt
Master->>SubAgent: scp /tmp/prompt.txt user@zt-ip:/tmp/review.txt
Master->>SubAgent: ssh user@zt-ip 'hermes chat --oneshot --query-file /tmp/review.txt'
SubAgent->>Master: Ergebnis (stdout)
Master->>Master: Prüft Ergebnis, baut bei Bedarf nächsten Prompt
```
## Prompt-Format (erfolgreich getestet)
```
PRUEFE FOLGENDE RESSOURCEN-SEITE AUF DESIGN-FEHLER:
CSS-Variablen (aktuell deployed):
--bg:#0f172a
--surface:#1e293b
--ink:#4ade80
ANTWORTE NUR MIT: "OK" ODER "FEHLER: <beschreibung>"
1. Ist --muted(#94a3b8) auf --surface(#1e293b) lesbar?
2. Ist die Card-Grid-Aufteilung sinnvoll?
3. Fehlt ein visuelles Element?
```
## Regeln
1. **NUR EIN Prüfpunkt pro Fachgebiet** — 3-5 eng verwandte Fragen in EINEM Prompt
(z.B. alle Kontrast-Fragen zusammen), aber NICHT Inhalt+Design+Code in einem Task
2. **Antwortformat erzwingen** — "ANTWORTE NUR MIT: OK ODER FEHLER: <beschreibung>"
3. **CSS-Werte direkt einbetten** — keine URL, kein Pfad, kein Verweis auf Master-Dateien
4. **hermes chat --oneshot** verwenden (nicht --query-file mit langen Sessions)
5. **Bei Tool-Limit:** Task war zu groß, z.B. bei UnraidHermes 11 Prüfpunkte scheiterten,
3-5 funktionierten. Noch kleiner schneiden.
6. **scp vor ssh** — Prompt-Datei auf Sub-Agent kopieren, dann erst ausführen
7. **PATH setzen** — Sub-Agenten haben `hermes` nicht in $PATH →
`PATH=/home/mehlzoerwer/.local/bin:/usr/bin:/bin hermes chat ...`
## Warum das funktioniert
- **Kein Dateisystem-Zugriff nötig** — der Prompt-Text kommt via scp auf /tmp/
- **Kein Tool-Limit durch file-reads** — der Agent muss keine URLs laden, keine Dateien suchen
- **Kein Permission-Problem** — /tmp/ ist für alle beschreibbar
- **Ein Checkpoint pro Durchlauf** — der Agent hat genau EINE Aufgabe: die 3-5 Fragen beantworten
- **Schnell** (~30s pro Agent, ~2 Min für Team-Review aller 3)
- **Kostengünstig** — ein Free-Modell ($0) für diese Mini-Tasks
## Fallstricke
- **Anführungszeichen im Prompt** — bei ssh-Befehl müssen einfache Anführungszeichen escaped werden.
Lösung: Prompt in Datei schreiben, scp, dann `--query-file` nutzen. KEINE inline-Prompts per
`ssh ... 'hermes chat -q "..."'` — das bricht bei Sonderzeichen.
- **Timeout** — `hermes chat --oneshot` kann bei Modell-Last 60s+ dauern.
`background=true, timeout=120` für die ssh-Ausführung.
- **kein Ergebnis** — wenn der Sub-Agent am Tool-Limit scheitert, kommt "noch nicht fertig".
Dann war der Prompt zu groß → noch kleiner schneiden.
- **Falsches Antwortformat** — manche Agenten ignorieren "ANTWORTE NUR MIT" und schreiben
Essays. Entweder Prompt verschärfen ("WENN DU MEHR SCHREIBST WIRD ES VERWORFEN") oder
die Antwort manuell parsen.
## Getestete Konfigurationen (01.09.2026)
| Agent | Erfolg | Dauer | Prompt-Größe |
|-------|--------|-------|-------------|
| UnraidHermes | ✅ OK (nur nach URL-Korrektur) | 47s | 11 Punkte → zu groß, scheiterte. 3 Punkte → OK |
| SwitchHermes | ✅ OK | 34s | 5 Design-Fragen |
| LaptopHermes | ✅ OK | 6s | 5 Tech-Fragen (gab nur "OK" zurück) |
## Voraussetzungen
- SSH-Key vom Master zum Sub-Agenten (ed25519, in `authorized_keys`)
- `scp` + `ssh` auf beiden Seiten
- Hermes auf dem Sub-Agenten installiert
- Kein NFS nötig
@@ -0,0 +1,72 @@
# SSH-Key-Verteilung & Master Control Suite (Praktischer Workflow)
> Stand: 31.08.2026 | Mesh mit 4 Agenten (Master + 3 Sub-Agenten)
## Problem: Master hat keinen SSH-Zugriff zu Sub-Agenten
SSH-Zugriff ist zwingend für Notfälle (Kill-Switch bei Budget-Spirale, Modell-Wechsel bei Kostenexplosion).
Tasks via NFS-Share sind zu langsam — Sub-Agenten analysieren lange Beschreibungen statt zu handeln.
## Versuchter Lösungsweg: AcceptMasterKey-Task (gescheitert)
Der Master generierte einen ed25519-Key und legte Tasks an alle Sub-Agenten mit dem Befehl:
```
mkdir -p ~/.ssh && echo '<pubkey>' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
```
**Problem:** Sub-Agenten in der Hermes-Sandbox haben kein `terminal()` — sie haben nur `execute_code` (Python).
Shell-Befehle (`mkdir`, `echo`, `chmod`) können sie nicht ausführen. Stattdessen *analysieren* sie den Task,
beschreiben die Lösung, setzen sie aber NICHT um. Task endet mit "BLOCKED" oder "muss fortgesetzt werden".
**Erkenntnis für Task-Formatierung:**
- `aufgabentyp: terminal` + nur `befehl:`-Feld = Sub-Agent führt NICHT aus (analyse)
- Lange Beschreibungen (5+ Zeilen) = Sub-Agent analysiert / halluziniert
- **Einzige Ausnahme:** Sub-Agent mit aktivem Gateway + Telegram-Zugang könnte per `hermes`-Terminal
des Master auf dem Sub-Agenten selbst gesteuert werden (Henne↔Ei: dafür braucht man SSH)
## Funktionierender Workaround: Manuelle Erst-Verteilung
Der Nutzer hat auf **jedem Sub-Agenten** kurz die zwei Befehle ausgeführt:
```bash
# 1. SSH-Key akzeptieren
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILEn0Vb4KKwbNI5wiT+Z7VWIiY6iiO7F4BeWS2gMWPCP mesh-master@172.24.196.119" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# 2. Modell setzen (je nach Agent)
hermes config set model.default google/gemini-2.5-flash:free # Unraid/Laptop
hermes config set model.default nvidia/nemotron-3-ultra-550b-a55b:free # Switch (Free Tier)
```
**Aufwand pro Agent:** ~30 Sekunden. **Einmalig.** Danach hat der Master volle SSH-Kontrolle.
## Master Control Suite (eingesetzte Tools)
Nach erfolgreicher SSH-Einrichtung stehen folgende Skripte auf dem Master zur Verfügung:
| Skript | Funktion | Cron |
|--------|----------|------|
| `mesh-kill-all.sh` | Notfall: Alle Agents auf Ollama (kostenlos) | Manuell |
| `mesh-budget-watch.sh` | Guthaben prüfen, Auto-Switch (Schwellen $1/$0.50/$0.10) | `*/30 * * * *` |
| `mesh-model-broadcast.sh <modell>` | Setzt Modell auf ALLEN Agents gleichzeitig | Manuell |
| `mesh-status-monitor.sh` | Trackt Task-Antworten + SSH, Telegram bei Änderung | `*/30 * * * *` |
| `mesh-model-scout.py` | OpenRouter-Preisliste scannen, Modell zuweisen | `0 6 */3 * *` |
| `mesh-budget-report.sh` | Guthaben + Modelle aller Agents als Telegram-Bullet-Liste | Manuell (Keyword/Telegram) |
**Budget-Report Format (Nutzerpräferenz):** Bullet-Liste statt Code-Block — auf Handy lesbar.
Telegram-Code-Blöcke mit Leerzeichen-Ausrichtung sehen auf Desktop gut aus, auf dem Handy (20 Zeichen
Breite) sind sie unleserlich. `• Agent — Modell`-Format rendert auf allen Geräten sauber.
Kein Doppel-Output (Skript schreibt direkt via curl an Telegram + stderr wird unterdrückt).
## SSH-Aktivierung (nach erfolgreicher Erst-Verteilung)
Verifikation durch:
```bash
for ip in 172.24.34.142 172.24.20.26 172.24.178.202; do
ssh -o BatchMode=yes -o ConnectTimeout=3 "mehlzoerwer@$ip" "echo OK"
done
```
Dienste danach automatisch abstimmen:
- Cron-Jobs auf Sub-Agenten pinnen: `hermes cron edit <id> --provider openrouter --model <modell>`
- OS-Updates per `echo '<pw>' | sudo -S apt update && sudo -S apt upgrade -y`
- Gateway auf Master als `systemctl enable hermes-gateway.service` (auto-start nach Reboot)
@@ -0,0 +1,56 @@
# SSH/scp Task-Polling statt NFS-Freigabe (Sicherheits-Umbau 2026-08-03)
## Entscheidung
NFS-Freigabe ist OBSOLET. Alle Sub-Agenten erhalten Tasks über **SSH/scp (Key-Auth, verschlüsselt)**.
Grund: NFS (sec=sys) überträgt plaintext → Man-in-the-Middle-fähig. SSH = Ende-zu-Ende verschlüsselt,
nur eigene Tasks sichtbar (gefiltert nach `*.C.D.*`), auditierbar.
`/srv/work/tasks/` bleibt als **zentrale Ablage auf dem Master** (offen/in_arbeit/fertig/bugfix/archiv),
nur die Zugriffsart änderte sich: kein Mount, sondern pull/push per scp.
## Warum NFS hier nicht überall geht
SwitchHermes = Ubuntu 24.04 auf Nintendo-Switch (Tegra-Kernel `4.9.140-l4t`):
- `modprobe nfs` → `FATAL: Module nfsv4 not found`
- NFS-Client + FUSE/sshfs fehlen (kein Kernelmodul, wenig Speicher → kein Kernel-Ausbau gewollt)
→ SSH/scp ist die einzige portable Methode für ARM-Switch-Geräte.
## Architecture des SSH-Poller-Daemons
- Jeder Agent hat **eigenen ed25519-Key** (auf Master: `/root/.ssh/<agent>_mesh`), Public-Key in `authorized_keys`.
- Poller-Script `mesh-agent-poller.sh <meine-IP> <meine-ID> [master] [keyfile]`:
1. `scp` pull eigene Tasks `offen/<JahrMonatTag>.<C>.<D>.*.json` nach `/tmp/mesh-tasks/`
2. Atomarer Lock **per SSH auf dem Master**: `mv offen/... in_arbeit/...` (absolute Pfade!), `&& echo OK || echo LOST`
3. Bearbeitung via `hermes chat -q "<PROMPT>" --quiet --max-turns 3`
4. Ergebnis als Base64 ins JSON-Feld `result` schreiben (SSH-python), dann `mv in_arbeit/ → fertig/`, chmod 0666
- **Daemon**: systemd-user-service (`~/.config/systemd/user/mesh-poller.service`, `Restart=always`, Loop alle 10s).
NICHT nohup/Cron-@reboot als Loop — der stirbt beim SSH-Session-Ende.
- Service-Start für User-Services: `export XDG_RUNTIME_DIR=/run/user/$(id -u); systemctl --user ...`
## Wichtigste Pitfalls (alle live getroffen)
1. **`SSH_CMD` MUSS den Host enthalten**: `SSH_CMD="ssh -i $KEY ... root@172.24.196.119"`.
Vergessen → `hostname contains invalid characters` + leerer Lock-Output = endlose SKIPs, obwohl der
manuelle `mv`-Test auf dem Master klappt.
2. **Relative Pfade im remote-mv vermeiden** — `../../../in_arbeit` geht 3 Ebenen hoch statt 1. Nutze absolute Pfade.
3. **Datei-Rechte (Hauptgrund, warum Polling anfangs nie lief):** vom Master (root) erstellte/durch `mv`
bewegte Task-Dateien behalten root-Owner → Sub-Agent (uid 1000) kann nicht reinschreiben, selbst bei
0777-Dir. Fix: **`chmod 0666`** nach Task-Erstellung (`mesh-task-create.sh`) UND nach jedem `mv` im Poller
(`in_arbeit` UND `fertig`). Sonst `PermissionError: [Errno 13]`.
4. **fail2ban bannt Mesh-IPs** bei scp-Fehlschlägen → `Connection refused` auf Port 22, obwohl Ping klappt
und sshd auf `0.0.0.0:22` lauscht. Fix: `ignoreip = <alle ZT-IPs>` in `[sshd]`-Sektion von
`/etc/fail2ban/jail.local`. Verifizieren: `fail2ban-client status sshd` → IP aus `Banned IP list` nehmen.
5. **Doppelte Daemon-Prozesse** (ein nohup-Rest + ein systemd-Rest) stören sich gegenseitig beim Lock.
Nach Umbau: `systemctl --user stop`, `pkill -9 -f mesh-poller-daemon`, PID-Datei löschen, sauber `start`.
Am Ende MUSS `pgrep -f mesh-poller-daemon` genau EINEN Prozess zeigen.
6. **"No such file or directory" beim remote-scp-Glob** kann heißen, dass der Task bereits in `fertig/`
liegt (ein früherer Lauf hat ihn gezogen). Erst `ls` auf Master prüfen, bevor man den Glob verdächtigt.
## NFS-Server deaktivieren (nach Migration)
- `systemctl stop/disable nfs-kernel-server rpcbind`
- `ufw delete allow from <ip> to any port 2049/111/20048` für jede Agenten-IP
- Offene Mesh-Ports danach NUR: 22 (SSH), 8644 (Webhook), 11434 (Ollama) — alle gerichtet auf die 4 bekannten ZT-IPs.
- `/etc/exports` bleibt als Datei liegen, aber inaktiv.
## NFS-Export-Härtung (falls man doch NFS nutzen muss)
Export auf die 4 bekannten IPs statt `/16`, zur
defense-in-depth: UFW-Regel (nur bekannte IPs) UND Export (bekannte IPs) konsistent:
`/srv/work/tasks ip1(rw,sync,no_subtree_check,no_root_squash) ip2(...) ...`
`exportfs -ra` reload separat ausführen, NICHT als gateway-gebundener Befehl (wird gekillt).