From 695fcf82f4a8a87127ce22e86faa967fd9009dc5 Mon Sep 17 00:00:00 2001 From: Jeuner <62662523+Jeuners@users.noreply.github.com> Date: Fri, 28 Aug 2026 16:04:38 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Handoff=20f=C3=BCr=20die=20n=C3=A4chste?= =?UTF-8?q?=20Sitzung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arbeitsnotiz mit Stand, den beiden nächsten Schritten (Export/Snapshots, Papierkorb) und dem zurückgestellten Cron-Entwurf. Dazu die Fallstricke dieser Sitzung, damit sie nicht zweimal Zeit kosten — vor allem das falsche gh-Remote, Ollamas effektives Kontextfenster und die Reihenfolge von onStats und onDone. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015AUP4R3rgq4XwVs4bVf7uh --- HANDOFF.md | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 HANDOFF.md diff --git a/HANDOFF.md b/HANDOFF.md new file mode 100644 index 0000000..59ab141 --- /dev/null +++ b/HANDOFF.md @@ -0,0 +1,115 @@ +# Handoff + +Stand: 28.08.2026. Arbeitsnotiz für die nächste Sitzung — kein Teil der +Projektdokumentation, die steht im [README](README.md). + +## Wo wir stehen + +Auf `main`: + +| Commit | Inhalt | +|-----------|--------------------------------------------------------------------------------------------| +| `8a489df` | Werkzeug-Bestätigung, DNS-Pinning, Statistik-Leiste, Produktionsbetrieb (Squash aus PR #1) | +| `a36e366` | Mic-/Anhang-Icons als SVG, blinkender Warte-Cursor | + +Arbeitsverzeichnis sauber, `npm run typecheck` und `vite build` grün. + +## Als Nächstes + +### 1. Export und Snapshots + +Anlass: Am 28.08. waren die vier Chats des Nutzers plötzlich weg. Rettbar +waren sie nur, weil die Löschungen noch im SQLite-WAL standen und der +Hauptfile den Stand des letzten Checkpoints hielt. Das war Glück, keine +Vorkehrung. + +- **Export** eines Chats als Markdown (Nachrichten, Anhänge als Dateinamen, + Werkzeugaufrufe optional). Naheliegender Ort: Button im Sidebar-Kontext + oder `GET /api/sessions/:id/export`. +- **Snapshot** der Datenbank: beim Serverstart und danach täglich eine Kopie + nach `server/backups/data-JJJJ-MM-TT.sqlite`, die letzten ~7 behalten. + Wichtig: `VACUUM INTO` statt `cp` — das schreibt einen konsistenten Stand + ohne WAL-Abhängigkeit. Verzeichnis in `.gitignore` aufnehmen. + +### 2. Papierkorb statt Sofortlöschung + +Der ✕-Button in `web/src/components/Sidebar.tsx:38` ruft `onDelete` ohne +jede Rückfrage. Am 28.08. sind so vier Chats mit 34 Nachrichten in 1,1 +Sekunden verschwunden (vier Klicks, je ~250 ms auseinander, jeweils auf den +obersten Eintrag, der nach dem Löschen nachrückt). + +- Spalte `deleted_at` in `sessions`; ✕ setzt sie, statt zu löschen +- Listenabfragen filtern `deleted_at IS NULL` +- Endgültiges Löschen nach 30 Tagen oder manuell im Papierkorb +- Optional zusätzlich: kurzes „Rückgängig" nach dem Klick + +Eine reine Bestätigungsabfrage wäre billiger, aber schwächer — sie schützt +nicht vor dem schnellen Durchklicken, das hier genau passiert ist. + +### 3. Datenbankpfad konfigurierbar machen (klein, aber Voraussetzung) + +`server/src/db.ts:5` hat den Pfad fest verdrahtet. Jeder Testlauf schreibt +damit in die echte Datenbank des Nutzers — genau das hat am 28.08. Testchats +in seiner Historie hinterlassen. Eine Variable `DB_PATH` (Default wie +bisher) erlaubt Tests gegen eine Wegwerf-Datei und gehört vor allem, was +automatisiert testet. + +## Später: geplante Aufgaben (Cron) + +Idee des Nutzers, bewusst zurückgestellt. Passt gut — Werkzeug-Loop, +Gedächtnis und TTS liegen bereit, und mit `dreamTimers` (`index.ts:71`) +existiert schon ein kleiner Scheduler. Zwei Punkte entscheiden das Design: + +**Bestätigungspflicht.** `read_webpage` und `remember` laufen nur nach +Freigabe, und ohne Rückkanal gilt „abgelehnt" (`tools/index.ts:107`). Ein +Job um 8 Uhr hat niemanden zum Fragen — ausgerechnet der nützlichste Job +würde zuverlässig scheitern. Auflösung: Freigabe wandert vom Ausführungs- +zum **Anlegezeitpunkt**. Beim Erstellen hakt der Nutzer die erlaubten +Werkzeuge an und sieht sie zusammen mit dem Prompt; der Job trägt diese +Allowlist als `ToolContext.confirm`. Das ist Einwilligung, nicht ihre +Umgehung. + +Dabei eng bleiben: `remember` **nicht** in die Standard-Allowlist. Ein +unbeaufsichtigter Job, der Fremdinhalt liest und daraus dauerhafte „Fakten +über den Nutzer" ableitet, ist genau die Kette, die der Security-Review +geschlossen hat. Jeder Job schreibt in einen eigenen Chat. + +**Laufzeit.** Cron feuert nur, solange der Server läuft; gestartet wird er +heute von Hand. Statt launchd lieber Verpasstes beim nächsten Start +nachholen — deutlich weniger Systemeingriff. + +## Offen beim Nutzer + +- Die vier wiederhergestellten Chats: unklar, ob die Löschung am 28.08. um + 15:02 Absicht war. Falls ja, gehören sie wieder raus. Sicherungen liegen + in `~/agenttwo-backups/` (`vor-wal.sqlite` = 8 Sessions inkl. vier + Testchats, `geloeschter-stand.sqlite*` = leerer Stand). +- Static-Serving im Entwicklungsbetrieb: seit `8a489df` liefert `:8788` auch + `web/dist` aus, sobald ein Build existiert — ein Standbild neben dem + lebenden Vite auf `:5174`. Abschaltbar über `NODE_ENV` im `dev`-Script, + bisher nicht gemacht. + +## Fallstricke, teuer gelernt + +- **`gh` zielt auf das falsche Repo.** Es löst auf `Jeuners/agenttwo` (das + `upstream`-Remote) auf, nicht auf `agenttwo-tools`. Ohne + `--repo Jeuners/agenttwo-tools` scheitert `gh pr create` mit einem + irreführenden „No commits between". Dauerhaft: + `gh repo set-default Jeuners/agenttwo-tools`. +- **Ollamas Kontextfenster ist nicht das deklarierte.** qwen3.5 meldet + 262144, geladen läuft es mit 4096. Der wahre Wert steht in + `GET /api/ps`, nicht in `/api/show`. +- **Emoji lassen sich nicht einfärben.** `🎙` und `📎` sind in den Fonts fest + grau. Zustandsfarben in CSS verpuffen an ihnen — deshalb jetzt SVG mit + `currentColor`. +- **`.caret` ist belegt** (Aufklapp-Dreieck des Denkprozesses). Der + Warte-Cursor heißt `.stream-caret`. +- **`onStats` muss vor `onDone` abgewartet werden.** Der `/api/ps`-Lookup ist + asynchron; ohne `await` geht die Stats-Nachricht hinter dem `done` raus und + der Client verwirft sie. Fiel nur auf, weil der erste (ungecachte) Lauf + leer blieb und der zweite nicht. +- **OpenRouters `usage` kommt nach `finish_reason`.** Ein früher Return + verschluckt die Tokenzahlen. Es braucht `stream_options.include_usage`. +- **Werkzeuge ohne Rückkanal werden abgelehnt.** Skripte und Tests, die + `runTool` direkt aufrufen, bekommen bei bestätigungspflichtigen Werkzeugen + „abgelehnt". Das ist Absicht — beim Testen ein `confirm` mitgeben.