docs: README holt den Nachmittag nach — Modelle, Datenschutz, Flugwetter, Overlay

Die README war vom Vormittag, danach kamen neun Commits. Keiner davon stand
drin.

Neu dokumentiert:
- Sprachmodell: Liste aus Anthropics Modell-Katalog, Tier vs. feste Version,
  Test-Knopf samt seiner vier Ergebnisse (inkl. dem gelben Fall "nicht
  erkannt", bei dem der Proxy still opus eingesetzt haette)
- Datenschutz-Schalter: die drei Sendekanaele, warum kein Neustart noetig ist,
  und warum eine per docker-compose gesetzte Variable als gesperrt erscheint
- Warnung bei veralteten Proxy-Patches (die Falle hat zweimal Zeit gekostet)
- Anhang-Limit, Zeitstempel/Sortierung/Zeitraum bei den Gedanken
- Overlay: wie es ohne feste Dauer wieder weggeht, und warum der
  Accessibility-Weg genommen wurde statt des naheliegenden
- flugwetter als Beispiel-Skill: Quellen mit Kosten, pc_met als dokumentierte
  Kundenschnittstelle, Seitenwind gegen Pistenrichtung, Herkunft pro Zahl

Neuer Abschnitt "Secrets und was bei Anthropic landet" unter den
Sicherheitsprinzipien. Der gehoert dorthin und nicht in eine Fussnote: alles
was ARIA sieht, wird uebertragen und gespeichert, und ob daraus Trainingsdaten
werden, haengt an einer Konto-Einstellung. Dazu die drei Regeln (nie in den
Chat, Zugangsdaten in die Konfiguration, oauth_call statt Token-Herausgabe) und
ehrlich auch die Grenze: ARIA laeuft mit Root im Proxy-Container und kann
/shared/config lesen, wenn sie hinschaut.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-03 12:42:57 +02:00
co-authored by Claude Opus 5
parent 517a8ea942
commit ae3a112868
+103 -2
View File
@@ -464,6 +464,44 @@ manueller Diagnostic-Klick) gehoeren seed_rules zum Brain-Code und werden
mit jedem Deploy ausgerollt. Editieren = `SEED_RULES`-Liste anpassen,
Brain neu starten.
### Beispiel: `flugwetter`
Zeigt gut, wie ein Skill mit Zugangsdaten und mehreren Quellen aussieht —
Briefing fuer **EDWI** (Wilhelmshaven-Mariensiel, Piste 02/20), nur mit
Python-Bordmitteln, keine pip-Pakete.
| Was | Woher | Kosten |
|---|---|---|
| METAR/TAF | aviationweather.gov | frei |
| Wind, Boeen | Open-Meteo **ICON-D2** | frei |
| Bedeckung, Sicht | DWD **MOSMIX** Station 10125 | frei |
| GAFOR, Karten | **ftp.pcmet.de** | Stefans pc_met-Konto |
Die pc_met-Zugangsdaten stehen in der **Skill-Konfiguration**
(`pcmet_user` / `pcmet_password`), nie im Chat. `ftp.pcmet.de` ist die vom DWD
dokumentierte Kundenschnittstelle — kein Nachbauen des Browser-Logins noetig.
`action=discover` listet, was auf dem Server liegt; `action=fetch` holt eine
Karte nach `/shared/uploads` und gibt sie als `[FILE:]`-Marker zurueck, sodass
ARIA sie anzeigen oder an einen Agenten schicken kann.
Zwei Dinge, die den Unterschied machen:
- **Seitenwind statt nur Wind.** Gerechnet gegen Piste 02/20 und gegen Stefans
15-kt-Grenze (`crosswind_limit_kt`), bewertet werden die **Boeen**.
- **Jede Zahl nennt ihre Herkunft.** Die Wolkenuntergrenze ist entweder
*gemessen* (METAR), ein ausdruecklich markierter *Schaetzwert*
(Temp/Taupunkt, 400-ft-Regel) oder *nicht verfuegbar* — dann steht da, dass
man ins GAFOR schauen muss. `CAVOK` wird als eigene Aussage behandelt und
unterdrueckt die Schaetzung, die sonst direkt widersprechen wuerde.
Genau daran war ein Briefing vorher gescheitert: METAR meldete `NCD`
(AUTO-Station), das Bodenmodell meldete bedeckt, und niemand wusste, was gilt.
Oben im Ergebnis steht eine **KURZFASSUNG in ganzen Saetzen zum Vorlesen**
(„fuenftausend Fuss", nicht „5000 ft") — eine vorgelesene Tabelle versteht
niemand. Fuer die Ausgabe auf einem Geraet kombiniert ARIA:
`run_flugwetter` → optional `action=fetch` → `host_notify(text=<Kurzfassung>,
image_path=<Karte>, mode='both', seconds=0)`.
---
## Diagnostic — Selbstcheck-UI und Einstellungen
@@ -473,7 +511,7 @@ Erreichbar unter `http://<VM-IP>:3001`. Teilt das Netzwerk mit der Bridge.
### Tabs
- **Main**: Brain/RVS/Proxy-Status, Chat-Test, "ARIA denkt..."-Indikator, **💭 Gedanken-Stream** (zentrales Modal, zeigt live alle Tool-Calls + Phasen mit Zeitstempel und Trennlinien bei langen Pausen), End-to-End-Trace, Container-Logs
- **Gehirn**: Memory-Browser (Vector-DB), Suche mit zwei Modi (**📝 Wortlich** = Substring-Match Default + **🧠 Semantisch** mit Score-Threshold), **Advanced Search** (aufklappbares Panel, beliebig viele AND/OR-verknuepfte Felder, + Button fuer mehr Zeilen), Type+Pinned-Filter (greifen auch in der Suche), klappbare Type-Kategorien (Default eingeklappt), Add/Edit/Delete mit Category-Autosuggest, **📎 Anhaenge** pro Memory (Bilder/PDFs/...): Upload + Thumbnail-Vorschau + Lightbox + Lösch-Button, 📎N-Badge in der Liste, automatischer Cleanup beim Memory-Delete. ℹ-Info-Modal das erklaert welche Types FEST in den Prompt vs. Cold Memory wandern. **📄 Druckansicht** (Strg+P → PDF). Konversation-Status mit Destillat-Trigger, **Token/Call-Metrics mit Subscription-Quota-Tracking**, Bootstrap & Migration (3 Wiederherstellungs-Wege), Gehirn-Export/Import (tar.gz)
- **Gehirn**: Memory-Browser (Vector-DB), Suche mit zwei Modi (**📝 Wortlich** = Substring-Match Default + **🧠 Semantisch** mit Score-Threshold), **Advanced Search** (aufklappbares Panel, beliebig viele AND/OR-verknuepfte Felder, + Button fuer mehr Zeilen), Type+Pinned-Filter (greifen auch in der Suche), klappbare Type-Kategorien (Default eingeklappt), Add/Edit/Delete mit Category-Autosuggest, **📎 Anhaenge** pro Memory (Bilder/PDFs/...): Upload + Thumbnail-Vorschau + Lightbox + Lösch-Button, 📎N-Badge in der Liste, automatischer Cleanup beim Memory-Delete. ℹ-Info-Modal das erklaert welche Types FEST in den Prompt vs. Cold Memory wandern. **📄 Druckansicht** (Strg+P → PDF). **Datum/Uhrzeit pro Gedanke** („angelegt 03.10.26, 09:14 · geändert … (vor 3 Std)") — `created_at`/`updated_at` lagen immer schon in der DB und wurden nur nie angezeigt. Dazu **Sortierung** (nach Typ gruppiert oder Anlage/Aenderung auf-/absteigend; bei Zeit-Sortierung flach statt gruppiert) und ein **🕒 Zeitraum-Filter** (von/bis, umschaltbar angelegt/geaendert, Schnellwahl Heute / 7 / 30 Tage) der auch fuer Such-Treffer gilt. Konversation-Status mit Destillat-Trigger, **Token/Call-Metrics mit Subscription-Quota-Tracking**, Bootstrap & Migration (3 Wiederherstellungs-Wege), Gehirn-Export/Import (tar.gz)
- **Skills**: Liste aller Skills mit Logs pro Run, Activate/Deactivate, Export/Import als tar.gz, "von ARIA"-Badge fuer selbst gebaute
- **Trigger**: passive Aufweck-Quellen. **Timer** (einmalig, ISO-Timestamp oder via `in_seconds` als Server-Berechnung) + **Watcher** (recurring, mit Condition + Throttle). Liste aktiver Trigger + Logs pro Feuer-Event. Modal mit Type-Dropdown, Live-Anzeige aller verfuegbaren Condition-Variablen (`disk_free_gb`, `hour_of_day`, `current_lat/lon`, `last_user_message_ago_sec`, …). **Drei GPS-Funktionen** mit unterschiedlicher Semantik:
- `near(lat, lon, r)` — SOLANGE im Radius (mit Throttle gegen Spam). Use-Case: „bin ich noch in der Nähe von X?"
@@ -505,7 +543,11 @@ Erreichbar unter `http://<VM-IP>:3001`. Teilt das Netzwerk mit der Bridge.
- **Debug-API ohne SSH** (Diagnostic-Server, Port 3001):
- `GET /api/chat-backup?lines=N` — letzte N Zeilen aus `chat_backup.jsonl` (Default 200, max 5000) als geparstes JSON. Hilfreich um nachzuvollziehen was ARIA tatsaechlich gemacht hat.
- `GET /api/agent-stream?lines=N` — gleiche Mechanik fuer den persistierten Live-Stream (Tool-Calls + Inputs + Outputs).
- **OAuth-Callback-Pipeline**: Caddy davor terminiert TLS via Let's Encrypt, RVS hat einen HTTP-Listener auf demselben Port wie der WebSocket. Provider (Spotify/Dropbox/Discord/...) redirecten den User an `https://{RVS_HOST}/oauth/callback/{service}` → RVS broadcastet als `oauth_callback`-WS-Message → aria-bridge forwarded an Brain → Brain matched `state`, tauscht `code` gegen Token, persistiert in `/shared/config/oauth_tokens.json`. Token-Refresh laeuft automatisch. ARIA hat vier Brain-Tools: **`oauth_register_provider`** (legt URLs eines neuen Providers wie Dropbox/Discord/Notion/... on-demand in `oauth_apps.json` an — Credentials bleiben Stefans Job), `oauth_authorize`, `oauth_get_token`, `oauth_revoke`
- **OAuth-Callback-Pipeline**: Caddy davor terminiert TLS via Let's Encrypt, RVS hat einen HTTP-Listener auf demselben Port wie der WebSocket. Provider (Spotify/Dropbox/Discord/...) redirecten den User an `https://{RVS_HOST}/oauth/callback/{service}` → RVS broadcastet als `oauth_callback`-WS-Message → aria-bridge forwarded an Brain → Brain matched `state`, tauscht `code` gegen Token, persistiert in `/shared/config/oauth_tokens.json`. Token-Refresh laeuft automatisch. ARIA hat fuenf Brain-Tools: **`oauth_register_provider`** (legt URLs eines neuen Providers wie Dropbox/Discord/Notion/... on-demand in `oauth_apps.json` an — Credentials bleiben Stefans Job), `oauth_authorize`, `oauth_get_token`, **`oauth_call`**, `oauth_revoke`
- **Sprachmodell**: die Auswahlliste kommt aus **Anthropics eigenem Modell-Katalog** (`downloads.claude.ai/model-catalog/v1/catalog.json`, Surface `cc`) — dieselbe Quelle, aus der sich Claude Code bedient. Oeffentlich, ohne API-Key. Oben die **Tier-Aliase** (opus/sonnet/haiku/fable), die automatisch der neuesten Version folgen; darunter die **exakten Versionen**, aeltere als solche markiert. „↻ Aktualisieren" holt frisch, sonst 6h-Cache mit Datei-Fallback fuer offline. **🔬 Testen** schickt eine echte Mini-Anfrage durch den ganzen Weg und zeigt, welches Modell tatsaechlich geantwortet hat (aus `modelUsage.canonicalModel` der CLI — das Modell selbst zu fragen waere unzuverlaessig). Vier Ergebnisse: Tier aufgeloest (gruen), exakte Version (gruen), **nicht erkannt** (gelb — der Proxy haette still `opus` eingesetzt), ungueltig (rot, mit CLI-Begruendung)
- **Datenschutz-Schalter**: die drei Kanaele, ueber die Claude Code zusaetzlich sendet (`DISABLE_ERROR_REPORTING`, `DISABLE_TELEMETRY`, `DISABLE_FEEDBACK_COMMAND`) pruefen und setzen. Geschrieben wird nach `~/.claude/settings.json` unter `env` — die CLI liest das bei jedem Aufruf, **kein Neustart noetig**. Geprueft wird, was wirklich im Prozess ankommt: eine per docker-compose gesetzte Variable gewinnt und wird als gesperrt angezeigt, statt einen wirkungslosen Haken anzubieten. **Nicht** dasselbe wie die Trainings-Einstellung — die steht im Anthropic-Konto (Link daneben)
- **Warnung bei veralteten Proxy-Patches**: der Proxy kopiert `proxy-patches/` beim **Start**. Wer nach einem `git pull` nur neu startet — oder neu startet, bevor der Pull durch ist — laeuft still mit der alten Fassung. Nichts deutet darauf hin. Die Einstellungen vergleichen jetzt die Zeitstempel und zeigen den fertigen Befehl (`--force-recreate proxy`)
- **Anhang-Limit** (System & Wartung): Groesse fuer Memory-Anhaenge, Default 64 MB. Liegt in `runtime.json`, das Brain liest es bei jedem Upload neu — greift sofort. Ueber 64 MB warnt die UI, weil die Handy-App darueber nichts mehr herunterlaedt
---
@@ -1067,6 +1109,26 @@ nichts zu tun. Auf dem Fire TV gibt es keinen Touchscreen, dafuer das D-Pad.
| Einblendung | Text ueber dem laufenden Bild (Overlay, braucht „Ueber anderen Apps anzeigen") |
| Sprache | ARIAs **echte** Stimme — der Agent fordert das Audio per `tts_request` ueber den normalen F5-TTS-Pfad an und spielt das PCM ab |
| Einstellung | Overlay oder Sprache als Standard, pro Anfrage ueberschreibbar (`mode`) |
| Bild + Text | `host_notify(image_path=/shared/uploads/...)` blendet ein Bild MIT Text ein — z.B. eine Wetterkarte |
**Wie die Einblendung wieder weggeht.** Eine feste Anzeigedauer ist immer
geraten: mal zu kurz zum Lesen, mal steht sie laengst im Weg. Darum bedeutet
`seconds=0`: **bleibt, bis Stefan etwas tut.**
- *Fernbedienung*: der Accessibility-Dienst bekommt `onKeyEvent` und raeumt die
Einblendung weg — gibt die Taste aber mit `return false` **weiter an den
Film**. Es geht kein Tastendruck verloren, der Player bleibt bedienbar.
- *Touch*: `FLAG_WATCH_OUTSIDE_TOUCH` meldet eine Beruehrung daneben; die geht
dank `FLAG_NOT_TOUCHABLE` gleichzeitig an die App darunter.
- *Notbremse*: nach 10 Minuten verschwindet sie in jedem Fall.
> Bewusst **nicht** der naheliegende Weg (Overlay faengt Tasten selbst ab):
> dafuer muessten `FLAG_NOT_FOCUSABLE` und `FLAG_NOT_TOUCHABLE` weg — und dann
> nimmt die Einblendung dem laufenden Film JEDE Eingabe, solange sie steht.
>
> Der Accessibility-Dienst braucht dafuer `canRequestFilterKeyEvents`. Nach
> einem Update also pruefen, ob er in den Bedienungshilfen noch aktiv ist —
> Android schaltet Dienste bei geaenderter Konfiguration gern ab.
> Fire TV Sticks haben oft **keine deutsche TTS-Engine**. Darum laeuft die
> Sprachausgabe bewusst nicht ueber die Geraete-Stimme, sondern ueber ARIAs
@@ -1147,6 +1209,40 @@ vorgeschlagen; nur wenn es keinen gibt, kommt der automatisch generierte.
6. **Panic Button**: `docker compose down` → sofort stoppen
7. **Alles loggen** — Stefan sieht immer was passiert
### Secrets und was bei Anthropic landet
ARIA laeuft ueber Claude Code auf einem Claude-Abo. **Alles, was ARIA sieht —
auch jedes Tool-Ergebnis — wird uebertragen und gespeichert.** Bei Consumer-
Plaenen (Free/Pro/Max) haengt es an einer Einstellung im Konto, ob daraus auch
Trainingsdaten werden; die Aufbewahrung betraegt entsprechend 5 Jahre oder
30 Tage ([claude.ai/settings/data-privacy-controls](https://claude.ai/settings/data-privacy-controls),
Details in Anthropics [Data-usage-Doku](https://code.claude.com/docs/en/data-usage)).
Daraus folgen drei Regeln:
1. **Secrets nie in den Chat tippen.** Das ist der Weg, ueber den hier
tatsaechlich einmal ein `client_secret` abgeflossen ist — nicht ueber ein
Tool, sondern weil es eingetippt und von ARIA zurueckzitiert wurde. Der
System-Prompt und die seed_rules weisen ARIA inzwischen an, das abzulehnen
und ein Secret nie zu wiederholen.
2. **Zugangsdaten gehoeren in eine Konfiguration, nicht in Code oder Chat.**
OAuth → Diagnostic → OAuth-Apps. Alles andere (Benutzername/Passwort,
API-Keys) → **Skill-Konfiguration** (`skill_set_config`), kommt zur Laufzeit
als `CFG_<NAME>` an und wird in der Oberflaeche maskiert.
3. **ARIA bekommt Zugangstokens nicht mehr zu sehen.** `oauth_get_token` sagt
nur noch, OB authentifiziert ist. Fuer API-Aufrufe gibt es **`oauth_call`**:
das Brain haengt die Authorization selbst an, fuehrt den Request aus und
gibt nur die Antwort zurueck — der Token verlaesst den Brain-Prozess nicht.
Abgesichert durch eine Host-Sperre: nur https und nur Hosts, die zum
Provider gehoeren (Vergleich auf den letzten zwei Labels, **nicht** per
`endswith` — sonst waere `boesespotify.com` durchgerutscht).
> Was ARIA NICHT schuetzt: sie laeuft mit Root im Proxy-Container und hat
> `/shared` gemountet. Sie *kann* `/shared/config/*.json` lesen, wenn sie
> hinschaut — und was sie liest, ist Tool-Ergebnis. Die Dateirechte (600)
> helfen dagegen nicht. Behandle jedes dort erreichbare Secret als
> „sichtbar, sobald ARIA hinschaut".
---
## Haeufige Befehle
@@ -1330,6 +1426,11 @@ docker exec aria-brain curl localhost:8080/memory/stats
- [x] **OpenAI-Endpunkt fuers lokale LLM** (+ optionales `openhands`-Profil); `.env` gewinnt immer, Diagnostic-Felder dann nur lesend
- [x] **Teilen-Ziel in der App** + **Sprachnachricht zu Anhaengen** + **Zwischenruf per Sprache**
- [x] **Trigger mit Projekt-Kontext**: die Antwort kommt dort zurueck, wo der Timer gestellt wurde (vorher immer Hauptchat), und `trigger_list` unterscheidet „schon gefeuert" von „deaktiviert"
- [x] **Modell-Liste von Anthropic** statt handgepflegt — und feste Versionen greifen wirklich. Vorher schmolz `extractModel` jeden unbekannten Namen still auf `opus` ein: eine bewusst gewaehlte Version wurde ohne Meldung durch eine andere ersetzt. Dazu ein **Test-Knopf**, der zeigt, welches Modell tatsaechlich geantwortet hat — moeglich wurde das erst, nachdem `normalizeModelName` aufhoerte, den echten Namen zu ueberschreiben
- [x] **Datenschutz**: die drei Claude-Code-Sendekanaele in der Diagnostic pruef- und abschaltbar (ohne Neustart), **`oauth_call`** statt Token-Herausgabe, Secrets-Regeln in Prompt und seed_rules, Warnung bei veralteten Proxy-Patches
- [x] **Anhang-Limit einstellbar** (Default 20 → 64 MB, greift sofort) und **Zeitstempel/Sortierung/Zeitraum** bei den Gedanken
- [x] **Flugwetter-Skill** mit pc_met-Anbindung, Seitenwind gegen Pistenrichtung und Herkunftsangabe pro Zahl; Ausgabe als Einblendung + Sprache auf einem Agenten
- [x] **Einblendung geht per Tastendruck weg** statt nach geratener Zeit — ueber `onKeyEvent` des Accessibility-Dienstes, der die Taste an den Film weiterreicht
#### Jagd auf verlorene Sprachnachrichten (die lange Kette)