21 Commits
Author SHA1 Message Date
RichardandClaude Opus 5 740649789e Eine Roadmap statt neun verteilter Listen
Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier
Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit
eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind
in docs/Roadmap.md zusammengefuehrt.

Aufbau der neuen Roadmap
- Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig /
  zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in
  einem Konzeptpapier zu verschwinden.
- Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1),
  damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen.
- Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach
  Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung,
  7 Herkunftskarte.

Was dabei sichtbar wurde
- Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten -
  allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in
  Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte.
- B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist
  keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A,
  warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute.
- Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren
  in keiner Roadmap verzeichnet.

Archiv
Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte
Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2
(gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und
der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber
nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt,
dass ihre Quelltext-Verweise ins Leere gehen koennen.

Bauplan bleibt Bauplan
Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und
Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe
fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile,
die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt.
Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der
Roadmap, nicht im Plan.

Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf
AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung
geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:31:06 +02:00
RichardandClaude Opus 5 2853541629 Fruehjahrsputz: WinForms-Altlast entfernt, Dokumentation nachgezogen
Die Avalonia-Portierung ist abgeschlossen, damit ist die in ClawdDotNet.slnx
angekuendigte Aufgabe "WinForms-Oberflaeche entfernen" faellig. Der Stand
davor liegt unter dem Tag vor-fruehjahrsputz-2026-08.

Entfernt (56 Dateien, seit dem Herausloesen der Anwendungsschicht nicht mehr
Teil des Builds): ClawdDotNet.csproj, Program.cs, sieben frm_*-Formulare,
UI/, Models/, EmbeddedUI/, Properties/, Resources/, Services/, das alte
Anwendungssymbol und Deploy-Build.ps1 (ersetzt durch deploy/publish.py).
Dazu configs/*.json - Beispielkonfigurationen aus der Zeit vor dem
Instanzverzeichnis, auf die nur noch die alten Prompts verwiesen.

Die vier Entwicklungs-Prompts der Anfangszeit ziehen nach docs/archiv/ um,
mit README, das ihren Stand einordnet. Eine Regel darin gilt weiter - die
Pflichtfelder fetchedAt/dataAsOf/source der Internet-Tools -, deshalb
Archiv statt Loeschen; der WebSearch-Plan verweist auf den neuen Pfad.

Toter Code
- PlaceholderPageViewModel samt Ansicht: Es gibt keinen Platzhalter-Bereich
  mehr, seit alle neun Seiten portiert sind.
- Snappier als direkter Paketverweis: MongoDB.Driver loest es ohnehin auf
  dieselbe Fassung auf, der Verweis hob nichts an.

Zwei Fehler, die dabei sichtbar wurden
- Die taegliche Sicherung lief ins Leere. Die Oberflaeche bot sie an und
  schrieb Uhrzeit, Zielordner und Anzahl in die Einstellungen, aber der
  BackupScheduler wurde nirgends erzeugt. Jetzt am AppHost verdrahtet und
  in den geordneten Abbau aufgenommen.
- SettingsPageViewModel hielt die vier Sicherungs-Einstellungen doppelt.
  Aus der Ansicht waren sie laengst verschwunden, gelesen und beim
  Speichern zurueckgeschrieben wurden sie weiter: Wer die Uhrzeit auf der
  Sicherungs-Seite aenderte und danach die Einstellungen speicherte, bekam
  den alten Wert zurueck.

Pakete: keine bekannten Sicherheitsluecken mehr
- SQLitePCLRaw.bundle_e_sqlite3 auf 2.1.13 angehoben. Microsoft.Data.Sqlite
  bringt 2.1.11 mit, darin steckt GHSA-2m69-gcr7-jv3q (NU1903, hoch).
- SharpCompress bleibt als direkter Verweis stehen. Beim Aufraeumen erst
  als ungenutzt entfernt - dabei kam die von MongoDB.Driver gezogene
  Fassung 0.30.1 mit GHSA-6c8g-7p36-r338 zurueck. Der Verweis ist eine
  Anhebung, kein Ballast; das steht jetzt als Kommentar dabei.

Dokumentation
- Roadmap mit Statusblock: A1 und A3 erledigt, A2 nur zur Haelfte - Gate,
  Policy und Dienst greifen, aber keine Ansicht ruft ApproveAsync auf, ein
  gestagter Aufruf liegt unbeantwortet. Das ist jetzt Punkt 1 der Reihung.
  Rocket.Chat steht und kollidiert mit A5 (Matrix) - Entscheidung faellig.
- Avalonia-Portierungsleitfaden -> Oberflaechen-Leitfaden: kein Auftrag mehr,
  sondern Beschreibung des Stands.
- Bestandsaufnahme und Linux-Analyse als datierte Befunde gekennzeichnet;
  der teure Teil der Linux-Analyse (8.900 Zeilen WinForms) ist hinfaellig.
- Verweise auf frm_*, WebView2 und ClawdDotNet.csproj in den lebenden
  Dokumenten richtiggestellt.

Build fehlerfrei, 585 Tests gruen (6 uebersprungen).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:26:14 +02:00
RichardandClaude Opus 5 33d95a6c3f UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem
Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag.

Oberflaeche
- Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als
  mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml
  (eigene ControlThemes statt Fluent umzufaerben).
- Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer
  Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite
  statt eigenem Fenster, Texteditor-Fenster.
- ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter
  entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt.

Rocket.Chat
- Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der
  Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird
  nur, wenn wirklich etwas anliegt.
- send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum
  ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist.
- Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei
  Annahmen waren falsch und sind korrigiert.

Deploymentcenter
- DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json)
  erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke.
- AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst
  ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:16:05 +02:00
Richard b5bf97ae74 feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar 2026-08-10 10:48:34 +02:00
RichardandClaude Opus 5 a0e18d2a57 Gitea-Token aus der Remote-URL entfernt, .gitignore-Ruecksicherung ergaenzt
Die Remote-URL enthielt das Zugriffstoken im Klartext
(http://Richard:<token>@192.168.178.10:8418/...). Damit stand es in
.git/config, in jeder Ausgabe von "git remote -v" und in der Shell-Historie.

Umgestellt auf denselben Weg wie PolyTrader, nur mit zentraler Token-Datei:
Remote ohne Zugangsdaten, Credential-Helper liest ~/.gitea-token. Ein Token
fuer alle Repos statt Kopien je Projekt — eine Rotation genuegt.

Anleitung und Pruefskript: J:\Softwareprojekte\GITEA-EINWEISUNG.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 14:56:25 +02:00
RichardandClaude Opus 5 61a93ffa58 Umsetzungsplaene fuer vier neue Agenten-Tools angelegt
Aus Richards Ideensammlung, nach Sichtung des vorhandenen Codes:

- FileRW-Papierkorb + Cleanup-Job: delete verschiebt nach .trash statt
  endgueltig zu loeschen, Aufraeumen ueber IToolJobProvider/ToolJobScheduler.
  Macht Loeschen reversibel und erlaubt damit, FileRW.delete im Staging von
  Approve auf Auto herunterzustufen.
- AgentInspector: lesende Aufsicht ueber andere Agenten. Beleg-basiert
  (Audit/Receipts/Taskboard) statt datei-basiert; harte Allowlist, damit
  AgentSettings.json mit den API-Keys nicht in einen LLM-Kontext geraet.
- AgentEditor-Haertung: Identity/Soul-Aenderungen ueber die vorhandene
  StagingPolicy freigabepflichtig machen, Selbstbearbeitung sperren,
  Audit + restore ergaenzen. Das Tool selbst existiert bereits.
- WebSearch: Suche als eigenes Tool, Lesen bleibt bei WebFetch hinter der
  Domain-Whitelist. Kein agent-reach (Klartext-Cookies, Fremdprozess).
  Trennung Rechercheagent / handelnder Agent gegen Prompt Injection.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 13:13:09 +02:00
RichardandClaude Opus 4.8 b51cc29667 Backup-Oberflaeche im Settings-Tab
Der BackupService bekommt eine Bedienoberflaeche im neuen Unterreiter "Backup".

Aufbau als eigenes UserControl (UI/BackupPanel) statt direkt in frm_main.Designer.cs.
Diese Datei ist ueber 1250 Zeilen gewachsene Handarbeit; ein Fehler beim Bearbeiten
waere teuer. Eingehaengt wird das Panel mit vier Zeilen.

Drei Bereiche: Sicherung erstellen (Zielordner, Umgang mit Zugangsdaten, Umfang),
automatische Sicherung (Uhrzeit, Aufbewahrungszahl) und die Liste vorhandener
Sicherungen mit Wiederherstellen, Anzeigen und Loeschen. Die Liste liest das
Manifest jeder Datei und zeigt Instanz und ob Zugangsdaten enthalten sind;
unlesbare oder fremde Archive werden ausgegraut mitgezeigt, statt sie zu
verschweigen.

Zwei Entscheidungen praegen das Verhalten.

Die Passphrase wird nirgends gespeichert. Laege sie neben den Sicherungen, waere
die Verschluesselung wirkungslos. Sie muss deshalb bei jeder geschuetzten
Sicherung neu eingegeben und wiederholt werden, und vor dem Erstellen wird
ausdruecklich bestaetigt, dass sie notiert ist — ohne sie sind die Zugangsdaten
unwiederbringlich. Die Automatik sichert aus demselben Grund ohne Zugangsdaten.

Wiederhergestellt wird standardmaessig in einen NEUEN Ordner neben der Instanz,
nicht ueber die laufende. Diese haelt Chatverlaeufe im Speicher und die Datenbank
geoeffnet — ein Ueberschreiben im Betrieb wuerde teils sofort wieder ueberschrieben
und teils scheitern. Der Dialog benennt das.

Vor dem Schreiben laeuft immer ein Probelauf: Er prueft die Pruefsummen und zaehlt
die Konflikte, sodass ein beschaedigtes Archiv auffaellt und Ueberschreiben
bestaetigt wird, bevor etwas passiert.

BackupScheduler sichert taeglich zur eingestellten Uhrzeit und wendet die Rotation
an. Der Zeitpunkt wird bei jedem Durchlauf neu aus den Einstellungen gelesen,
damit eine Aenderung ohne Neustart greift.

Die Oberflaeche ist noch nicht optisch geprueft — die Dev-Instanz haelt einen
echten API-Key und wuerde beim Start Agenten ausfuehren.

385 Tests gruen (237 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 10:37:16 +02:00
RichardandClaude Opus 4.8 b55512e734 Backup und Wiederherstellung einer Instanz
Gesichert wird alles, was sich nicht wiederherstellen laesst: Identity und Soul,
Konfigurationen, Arbeitsverzeichnisse, Chatverlaeufe und vor allem die Datenbank
mit dem Langzeitgedaechtnis. Protokolle bleiben standardmaessig aussen vor.

Zwei Punkte waren dabei nicht offensichtlich.

Die Datenbank darf nicht einfach kopiert werden. Mit WAL stehen die juengsten
Aenderungen in der Begleitdatei, nicht in der Hauptdatei — eine reine Kopie waere
veraltet oder in sich widersprueckhlich. VACUUM INTO erzeugt dagegen im laufenden
Betrieb eine geschlossene, konsistente Kopie; die WAL-Begleitdateien gehoeren dann
nicht mehr ins Archiv.

Zugangsdaten sind seit S7 mit DPAPI geschuetzt und damit an Benutzer und Rechner
gebunden. In einer Sicherung waeren sie genau dann unbrauchbar, wenn man sie
braucht — bei einem defekten Rechner. PassphraseProtector schluesselt sie deshalb
beim Sichern auf eine Passphrase um (PBKDF2 mit 210.000 Runden, AES-GCM) und beim
Wiederherstellen zurueck auf DPAPI des Zielrechners. Alternativ laesst sich eine
Sicherung ganz ohne Zugangsdaten erstellen; sie ist dann gefahrlos ablegbar, die
Wiederherstellung aber unvollstaendig.

Das Umschluesseln arbeitet auf dem JSON-Baum statt ueber die typisierten
Konfigurationsklassen. Beim Deserialisieren und erneuten Serialisieren gingen
unbekannte Felder verloren — eine Sicherung darf aber nichts wegwerfen, nur weil
eine Programmfassung ein Feld nicht kennt. Ein Test haelt das fest.

Weitere Eigenschaften: Manifest mit Pruefsummen je Datei, sodass ein veraendertes
Archiv auffaellt, bevor etwas ueberschrieben wird. Vorschau-Modus. Vorhandene
Dateien werden ohne ausdrueckliche Zustimmung nicht ueberschrieben. Eintraege, die
aus dem Zielverzeichnis herauszeigen, werden abgelehnt.

Der wichtigste Test ist der vollstaendige Rundlauf: Instanz aufbauen, sichern, in
ein leeres Verzeichnis wiederherstellen und pruefen, dass Persoenlichkeit,
Arbeitsstand, Gedaechtnis und nutzbare Zugangsdaten zurueck sind. Ein ungepruefte
Wiederherstellung ist kein Backup, sondern eine Vermutung.

385 Tests gruen (237 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 15:00:42 +02:00
RichardandClaude Opus 4.8 1157d28588 Konfig- und Zustandsdateien atomar schreiben
File.WriteAllText kuerzt die Zieldatei zuerst auf null und fuellt sie dann. Bricht
der Vorgang dazwischen ab, ist der alte Inhalt weg und der neue unvollstaendig.

Das ist im Betrieb bereits eingetreten: In der Instanz TradingTeam lag eine
TokenUsage.json.corrupt_..., die die Fehlerbehandlung beiseitegelegt hatte. Der
Verbrauch bis dahin war verloren.

AtomicFile schreibt in eine Nebendatei, erzwingt das Schreiben auf die Platte und
ersetzt dann. Umgestellt sind ChatHistory, ChatContext, alle Instanz- und
Agentenkonfigurationen, Identity und Soul, die App-Einstellungen sowie der
Stock-Index.

Zum Ersetzen wurde das Windows-Verhalten gemessen statt vermutet. Mit einem Leser,
der die Zieldatei geoeffnet haelt:

  Freigabe des Lesers      File.Move   File.Replace
  Read                     scheitert   scheitert
  ReadWrite                scheitert   scheitert
  ReadWrite | Delete       scheitert   funktioniert

File.Move verlangt die Zieldatei exklusiv und scheitert deshalb immer, sobald
jemand sie geoeffnet hat. Daher File.Replace — und ein Lesehelfer
AtomicFile.ReadAllText, der das Loeschen freigibt, damit unsere eigenen Leser
keinen Schreiber blockieren. Die Leser in InstanceDirectoryManager und beim Laden
der Chatverlaeufe nutzen ihn jetzt.

Zusaetzlich ein Schloss je Zieldatei: Zwei gleichzeitige Schreibvorgaenge auf
dieselbe Datei sind ohnehin ein Rennen, ohne Serialisierung scheitern sie aber
zusaetzlich mit "Zugriff verweigert". Fuer fremde Leser wie Virenscanner bleibt
eine Wiederholung mit Wartezeit.

366 Tests gruen (218 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 09:47:38 +02:00
RichardandClaude Opus 4.8 ef3e519f6c K5: Tagesbudget als harte Grenze
Es gab keine Obergrenze. Ein Agent in einer Schleife — etwa durch gegenseitige
send_message-Aufrufe — konnte unbeaufsichtigt Guthaben verbrennen; die
Credits-Anzeige war rein informativ.

Verbrauchsdaten in der Datenbank

Voraussetzung dafuer ist eine belastbare Erfassung. Bisher lag der Verbrauch in
TokenUsage.json: Bei JEDEM Agenten-Lauf wurde die gesamte Datei geladen, ergaenzt
und neu geschrieben, unter einem globalen Lock. Das waechst quadratisch und ist
der eigentliche Engpass bei vielen Agenten — unabhaengig davon, welche Datenbank
darunter liegt.

RunUsage liegt jetzt in einer eigenen Tabelle mit Ortsdatum, damit ein Tagesbudget
der Wahrnehmung des Benutzers folgt und die Abfrage ohne Zeitzonenrechnerei
auskommt. Betraege werden als Text abgelegt und als decimal gelesen: Ueber REAL zu
gehen wuerde bei Cent-Betraegen Rundungsfehler einsammeln, die sich ueber tausende
Laeufe summieren. Ein Test weist das mit 1000 Buchungen zu je 0,0001 USD nach.

BudgetGuard

Zwei Arten von Grenzen, weil sich Kosten nicht immer beziffern lassen: Liefert der
Anbieter fuer ein Modell keine Preise, greift die Kostengrenze nicht — die
Token-Grenze dagegen immer. Wer sich absichern will, setzt beide. Ist die Summe
wegen fehlender Preise unvollstaendig, steht das in der Begruendung; sonst wirkte
ein niedriger Verbrauch wie ein noch offener Spielraum.

Grenzen gibt es je Agent und je Instanz. Geprueft wird vor der ersten Anfrage,
damit ein erschoepftes Budget gar nichts mehr kostet. Neuer Endzustand
BudgetExceeded.

Nebenbei: Der Namespace Usage kollidierte mit der gleichnamigen Modellklasse fuer
Token-Angaben und heisst jetzt Accounting.

357 Tests gruen (209 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 18:16:21 +02:00
RichardandClaude Opus 4.8 4747835fa1 K1: Langzeitgedaechtnis fuer Agenten
Geplante Agenten begannen bei jedem Cron-Lauf bei null. Ein Agent, der alle 30
Minuten lief, wusste nichts von seinem letzten Durchgang — er rief dieselben
Quellen ab, zog dieselben Schluesse und konnte keine Entwicklung ueber Zeit
verfolgen. Das war zugleich die groesste Faehigkeitsluecke und eine dauerhafte
Token-Verschwendung.

Speicher-Fundament

SqliteStorage buendelt den Zugang zur Instanz-Datenbank und aktiviert WAL,
busy_timeout und Connection-Pooling. Vorher oeffnete jeder Aufruf eine Verbindung
ohne diese Einstellungen; bei mehreren gleichzeitig schreibenden Agenten gab das
"database is locked". Das sah nach einer Grenze von SQLite aus, war aber nur
fehlende Konfiguration. Zwei Tests decken das gezielt ab.

Gedaechtnis

Typisierte Tabelle statt JSON in einer Wert-Spalte — nur so laesst sich filtern,
sortieren und spaeter auswerten. Das Schema ist schlicht gehalten, damit eine
MySQL-Variante spaeter dieselbe Struktur mit wenigen Dialektunterschieden
bekommen kann.

Der wichtigste Teil ist der optionale Schluessel: Erneutes Merken darunter
aktualisiert den Eintrag, statt einen zweiten anzulegen. Ohne das wuechse das
Gedaechtnis eines halbstuendlich laufenden Agenten um 48 Eintraege pro Tag zur
selben Sache. Beobachtungen ohne Schluessel sammeln sich weiterhin an, wenn ein
Verlauf entstehen soll.

Der Abruf sortiert nach Wichtigkeit, dann Aktualitaet — wesentlich, weil das
Ergebnis begrenzt wird und bei einer Kappung das Wichtigste ueberleben muss.
Zusaetzlich greift eine Zeichenobergrenze, damit ein Abruf den Kontext nicht
sprengt.

Die Trennung privat/geteilt ist absichtlich dieselbe wie beim FileRW-Tool, damit
das Konzept fuer Agenten wiedererkennbar bleibt.

Beim Testen fiel auf, dass das Maskieren der LIKE-Platzhalter falsch war: Die
Zeichen wurden entfernt statt maskiert, wodurch eine Suche nach einem
Prozentzeichen zu einem leeren Muster und damit zu einem Treffer auf alles wurde.
Jetzt mit ESCAPE-Klausel.

338 Tests gruen (190 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 10:44:39 +02:00
RichardandClaude Opus 4.8 8604fa30c7 S7: Zugangsdaten in Konfigurationsdateien verschluesseln
OpenRouter-Schluessel, Datenbank-Verbindungszeichenfolgen samt Passwort,
Mail-Zugangsdaten und das Telegram-2FA-Passwort lagen im Klartext in
AgentSettings.json und InstanceSettings.json. Wer die Dateien lesen konnte — ein
Backup, eine Dateifreigabe, ein versehentlicher Commit — hatte alle Zugaenge.

SecretProtector nutzt DPAPI im Benutzerkontext: Die Werte lassen sich nur vom
selben Windows-Benutzer auf demselben Rechner lesen. Das schuetzt gegen
Weitergabe der Datei, nicht gegen einen Angreifer, der bereits als dieser
Benutzer laeuft — fuer einen lokal laufenden Dienst die angemessene Stufe.

Verschluesselte Werte tragen ein Praefix. Dadurch bleibt Klartext aus bestehenden
Konfigurationen lesbar und wird beim naechsten Speichern automatisch uebernommen;
vorhandene Installationen laufen ohne Zutun weiter.

Ein Wert, der sich nicht entschluesseln laesst — etwa nach Benutzer- oder
Rechnerwechsel — wird gemeldet statt stillschweigend als Klartext
durchgereicht. Sonst ginge ein unbrauchbarer Schluessel an die API und der
Fehler waere schwer zuzuordnen.

ConfigSecrets entscheidet anhand der Feldnamen, welche Werte betroffen sind. Das
ist noetig, weil die Tool-Konfiguration ein freies Woerterbuch ist. Beim Speichern
werden die Werte nur fuer den Schreibvorgang verschluesselt und danach wieder
entschluesselt, damit die laufende Instanz weiterarbeiten kann.

309 Tests gruen (161 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 10:21:08 +02:00
RichardandClaude Opus 4.8 93f47aca3a Modellpreise live vom Anbieter beziehen
Zweiter Teil von B4. Die Preise standen fest im Code — eine Tabelle mit einer
Handvoll Modelle, die bereits veraltet war. Ausgerechnet das Standardmodell der
Agenten fehlte darin, und CalculateCost gab fuer unbekannte Modelle
stillschweigend 0 zurueck. Die Kostenanzeige war damit nicht bloss ungenau,
sondern blind: Sie meldete 0 Euro, waehrend echte Kosten anfielen.

ModelInfo traegt jetzt die Preisangaben aus dem /models-Endpunkt. OpenRouter
liefert sie als Text und pro einzelnem Token; die Umrechnung auf eine Million
Token laeuft ueber InvariantCulture, sonst wuerde eine deutsche Systemsprache
0.000003 als drei lesen.

Halbe Angaben werden verworfen: Ein Modell, bei dem nur der Eingabepreis
vorliegt, ergaebe eine plausibel aussehende, aber falsche Summe.

ModelPricingCatalog haelt die Preise und liefert eine Kostenschaetzung, die
ausweist, ob sie belastbar ist. Der Statusdienst laedt den Katalog beim Start und
markiert Laeufe ohne Preisangabe sichtbar — in der Zeile mit einem Warnzeichen,
im Tooltip mit den betroffenen Modellnamen und dem Hinweis, dass die Summe
unvollstaendig ist.

284 Tests gruen (136 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 10:09:39 +02:00
RichardandClaude Opus 4.8 cbb8ac22bc SSRF-Schutz, Pfadpruefung und Retry-Logik
S5 — Die Domain-Whitelist wurde nur auf die Ausgangs-URL angewendet, HttpClient
folgte Weiterleitungen aber selbst. Eine erlaubte Domain konnte damit auf
beliebige interne Adressen weiterleiten: Router, NAS, der Git-Server im LAN,
Cloud-Metadatendienste. Der Agent haette deren Inhalt zurueckgeliefert.

UrlGuard prueft Schema, private und lokale Netzbereiche sowie die Whitelist.
AllowAutoRedirect ist abgeschaltet; Weiterleitungen werden einzeln aufgeloest und
JEDER Zwischenschritt erneut geprueft, begrenzt auf fuenf Spruenge.

Nebenbei behoben: Die alte www-Behandlung ersetzte die Zeichenfolge ueber den
ganzen Hostnamen, aus mywww.example.com wurde myexample.com. Und die
Subdomain-Pruefung achtet jetzt auf den Punkt, sodass example.com.attacker.net
nicht mehr als Treffer fuer example.com durchgeht.

S6 — Die Pfadpruefung in FileRW verglich nur Zeichenketten-Praefixe. Ohne
abschliessenden Verzeichnistrenner erlaubte ein Root wie Agent-X\Workspace damit
auch Zugriffe auf Agent-X\Workspace-Backup. WorkspacePath vergleicht jetzt auf
Verzeichnisgrenzen und lehnt zusaetzlich absolute Pfade, UNC-Freigaben und
Alternate Data Streams ab.

Das Dateisystem wird in den Tests bewusst nicht abstrahiert — sie sollen die
echte Windows-Pfadsemantik pruefen. Eine Abstraktion wuerde genau die
Fehlerklasse verstecken, um die es geht.

B12 — Der Client warf bei jedem Nicht-2xx sofort; ein einzelnes HTTP 429 beendete
damit einen kompletten geplanten Lauf, obwohl Rate-Limits und kurze 5xx bei
OpenRouter Normalbetrieb sind. RetryPolicy wiederholt 408/425/429/5xx mit
exponentiellem Backoff und Streuung, respektiert ein Retry-After des Servers und
deckelt die Wartezeit. Dauerhafte Fehler wie 401 werden nicht wiederholt.

Die Wartefunktion ist injizierbar, damit die Tests nicht wirklich warten.

264 Tests gruen (116 Core, 148 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 00:24:03 +02:00
RichardandClaude Opus 4.8 e5067cae70 Sicherheitsluecken S1, S2 und S3 schliessen
Neues Testprojekt tests/ClawdDotNet.Tools.Tests. Die Angriffsfaelle aus der
Bestandsaufnahme bleiben darin dauerhaft als Testfaelle dokumentiert — zusammen
mit Gegenproben, damit die Fixes nicht zu streng werden und legitime Nutzung
blockieren.

S3 — DirectAPI gab die abgerufene URL als Quelle an das Modell zurueck, samt
API-Schluessel im Query-String. Der Schluessel landete damit im
Konversationskontext, wurde bei jedem Folgeschritt erneut gesendet, in
ChatContext.json geschrieben und in die Logs uebernommen. UrlSanitizer maskiert
sensible Query-Parameter; auch die Fehlermeldungen sind betroffen und werden
bereinigt.

S2 — Die Kanal-/Video-Angabe wurde ungeprueft in eine Argument-Zeichenkette fuer
yt-dlp interpoliert. UseShellExecute=false verhindert Shell-Metazeichen, nicht
aber Options-Injection: yt-dlp kennt die Option --exec, die beliebige Befehle
ausfuehrt. Kritisch, weil der Agent untrusted Inhalte verarbeitet — eine
Prompt-Injection darin konnte ihn dazu bringen, genau so einen Wert zu setzen.

YouTubeUrl validiert Handles und URLs gegen die zulaessigen YouTube-Hosts und
lehnt alles ab, was mit einem Bindestrich beginnt. Die Argumente gehen jetzt
einzeln ueber ProcessStartInfo.ArgumentList, die Adresse steht hinter dem
Optionsende-Trenner. Der ffmpeg-Aufruf wurde ebenso umgestellt.

S1 — Die Tabellen-Whitelist suchte den erlaubten Namen als Teilzeichenkette
irgendwo im Statement, auch in Kommentaren. Bei einer Freigabe fuer prices
genuegte deshalb ein DELETE auf users mit einem Kommentar, der prices enthielt,
um eine beliebige Tabelle zu loeschen. Umgekehrt galten harmlose Abfragen, die
ein Schluesselwort nur als Wert enthielten, faelschlich als Schreibzugriff.

SqlGuard entfernt zuerst Kommentare und String-Literale, lehnt mehrere Statements
ab, bestimmt die Operation am ersten Schluesselwort und extrahiert Tabellennamen
gezielt hinter FROM/JOIN/INTO/UPDATE/TABLE — inklusive kommagetrennter Listen mit
Aliassen. JEDE referenzierte Tabelle muss freigegeben sein, nicht irgendeine.
Ohne Whitelist wird nichts durchgelassen. Die MongoDB-Pruefung vergleicht den
Collection-Namen jetzt exakt statt per Teilzeichenkette.

178 Tests gruen (91 Core, 87 Tools).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:49:17 +02:00
RichardandClaude Opus 4.8 69b5704add Prompt-Caching, Tool-Ergebnis-Kappung und Kostenerfassung
T1 — Prompt-Caching. Bisher wurde bei jedem Schritt eines Runs der komplette
Prompt neu berechnet, inklusive Tool-Definitionen und System-Prompt, die sich nie
aendern. Bei zehn Schritten und einem 15k-Praefix sind das 150.000 statt 15.000
Eingabe-Tokens.

ChatMessage bekommt dafuer einen eigenen JsonConverter: Der Inhalt geht weiterhin
als String raus, bei gesetztem CacheBreakpoint jedoch als Blockarray mit
cache_control. Beim Lesen werden beide Formate akzeptiert, damit bestehende
ChatContext.json weiter geladen werden koennen.

PromptCache setzt zwei Breakpoints: einen auf den System-Prompt (deckt
Tool-Definitionen und System-Prompt ab) und einen rollierenden auf die letzte
Nachricht mit Inhalt. Vorherige Markierungen werden vorher entfernt, damit sie
sich nicht ansammeln. Aktivierung ueber promptCaching: auto (Default, aktiv fuer
Modelle mit Unterstuetzung), on oder off.

Der wichtigste Test dazu prueft die Praefix-Stabilitaet: Der System-Prompt muss
ueber alle Schritte zeichengleich serialisiert werden. Ein einziger Zeitstempel
darin wuerde den Cache still verwerfen — die Kosten blieben unveraendert, ohne
dass es irgendwo auffiele.

T9 — Usage liest prompt_tokens_details.cached_tokens; die Zahl wird bis in
AgentRunResult durchgereicht. Ohne sie liesse sich die Wirkung nicht belegen.

T2 — Tool-Ergebnisse werden jetzt zentral in ExecuteToolCallAsync gekappt
(maxToolResultChars, Default 16.000). Bisher konnte ein einzelner WebFetch mit
dem 512-KB-Standardlimit rund 130.000 Tokens in EINER Antwort erzeugen; die
Compaction griff erst danach, bezahlt war der Request laengst.

T3 — Die Zusammenfassung beim Kompaktieren laeuft ueber ein konfigurierbares
summaryModel (Default gemini-2.5-flash) statt ueber das teure Agentenmodell.

B4 — AgentRunResult fuehrt Prompt- und Completion-Tokens getrennt; die
Kostenanzeige schaetzte bisher 50/50, real liegt das Verhaeltnis eher bei 95:5.
Die veraltete Preistabelle bleibt offen.

Neue Einstellungen sind im PropertyGrid sichtbar und werden vom AgentEditor bei
neuen Agenten mitgeschrieben.

Alle 91 Tests gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:32:17 +02:00
RichardandClaude Opus 4.8 6bbe9f9a80 B2 beheben: Chat-Laeufe pro Agent serialisieren
Der Konversationskontext _chatContexts[agentId] ist eine geteilte List<ChatMessage>.
Nur der Lookup lief unter Lock, alle Add-Aufrufe im Schleifenkoerper waren
ungeschuetzt. Da WebView, ToolJob-Wakeups und AgentComm denselben Agenten
gleichzeitig ansprechen koennen, verschraenkten sich ihre Nachrichten zu einer
ungueltigen Tool-Sequenz, die die API mit HTTP 400 ablehnt.

ChatAsync laeuft jetzt hinter einem SemaphoreSlim(1,1) pro Agent; verschiedene
Agenten bleiben unabhaengig. Die Timeout-Uhr startet erst nach dem Eintritt,
damit Wartezeit in der Warteschlange den Lauf nicht aufzehrt.

Zwei Folgeprobleme mit demselben Ursprung:

- _runningChats hielt nur EINE CancellationTokenSource je Agent; der zweite Lauf
  ueberschrieb den ersten. AbortChat brach dadurch nur einen ab, der andere lief
  bis ins Run-Timeout. Jetzt eine Liste, die auch wartende Laeufe erfasst.
- ExecuteToolCallAsync fing OperationCanceledException mit ab und gab sie als
  Tool-Ergebnis zurueck, wodurch der Abbruch erst einen Schritt spaeter griff.
  Cancellation wird nun durchgereicht.

Ausserdem: send_message an den eigenen Agenten wird abgelehnt — es waere mit dem
neuen Gate in einen Deadlock gelaufen.

Neu: GetChatContext(agentId) als Momentaufnahme des Kontexts, fuer Diagnose und
Kontextgroessen-Anzeige.

Build-Fix: Das WinForms-Projekt globbt **/*.cs und kompilierte dadurch die
Test-Quellen mit. tests\** wird jetzt wie src\** ausgeschlossen.

Alle 49 Tests gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 10:55:04 +02:00
RichardandClaude Opus 4.8 eae13771cf B1, B14 und B3 beheben: Compaction-Paarung und Token-Semantik
B1 — Die Compaction behielt blind die letzten 6 Nachrichten. Fiel diese Grenze
mitten in eine Tool-Sequenz, entstand eine tool-Antwort ohne zugehoerigen
assistant-tool_call; die API lehnt das mit HTTP 400 ab. FindSafeTailStart
verschiebt die Grenze jetzt rueckwaerts auf eine Blockgrenze.

B14 — Bei Konversationen mit hoechstens 6 Nachrichten enthielt der Tail auch die
system-Nachricht, die anschliessend ein zweites Mal angehaengt wurde. Ergebnis
war ein doppelter System-Prompt und eine duplizierte Konversation — die
Compaction vergroesserte den Kontext, statt ihn zu verkleinern. Der Tail beginnt
nun grundsaetzlich hinter dem System-Prompt; liegt davor nichts Nennenswertes,
wird die Kompaktierung uebersprungen. Gefunden durch den Property-Test.

Nebeneffekt: Zusammengefasst wird nur noch der Teil, der tatsaechlich wegfaellt.
Der Tail bleibt woertlich erhalten und musste bisher doppelt bezahlt werden.

B3 — maxTokens zaehlte kumulativ ueber alle Schritte, wurde aber wie eine
Kontextgrenze konfiguriert. Da jeder Schritt den vollen Kontext erneut sendet,
brach ein Chat mit 20k Kontext nach vier Schritten ab. Aufgeteilt in
maxCumulativeTokens (Kostenbudget, Default 500k) und maxContextTokens
(Kontextgroesse). Alte Konfigurationen werden beim Laden migriert, die
Fehlermeldungen unterscheiden jetzt Schritt- und Kostenlimit.

Alle 31 Tests gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 10:15:50 +02:00
RichardandClaude Opus 4.8 667cecce25 Testfundament aufbauen und Bestandsaufnahme dokumentieren
IChatCompletionClient aus OpenRouterClient extrahiert, damit AgentEngine und
ContextCompactor ohne echte API-Aufrufe testbar sind.

Neues Testprojekt tests/ClawdDotNet.Core.Tests (xUnit, Shouldly, NSubstitute,
FsCheck) mit:
- FakeChatClient (programmierbare Antwortfolgen, Deep-Copy der Requests)
- ContextInvariants (prueft die API-Regeln fuer tool_call-Paarung)
- Conversation-Builder fuer gueltige Testkonversationen
- 26 Tests: Compaction, LoopGuard, 2 Property-Tests

10 Tests sind bewusst rot — sie reproduzieren die Bugs B1, B3 und B14 aus der
Bestandsaufnahme und werden mit den Fixes gruen.

Ausserdem: fehlende Tool-Projekte in slnx ergaenzt, Test-Pakete im
packageSourceMapping der NuGet.Config eingetragen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 10:07:54 +02:00
RichardandClaude Opus 4.8 92e50d3ac4 Add .gitattributes for consistent line endings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 18:22:12 +02:00
RichardandClaude Opus 4.8 2fed388c99 Initial commit: ClawdDotNet
Import des bestehenden Projektstands in Git.
- .NET 10 WinForms Anwendung (Multi-Agent / Tool-System)
- .gitignore fuer Build-Artefakte, Secrets und Runtime-Daten ergaenzt

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 18:21:46 +02:00