6.9 KiB
ToDo-App mit autonomem Agent-Worker — Design
Context
Ziel: eine persönliche ToDo-App als Desktop-Anwendung, in der mehrere Listen verwaltet werden können. Ein Teil der Tasks soll autonom von Claude abgearbeitet werden (z.B. Recherche, Code-Aufgaben, Notizen-Verarbeitung). Die Autonomie läuft in einem getrennten Hintergrund-Prozess, damit die UI davon entkoppelt bleibt.
Motivation: Aufgaben "parken" und später von einem Agenten abarbeiten lassen, ohne dafür manuell einen Chat zu öffnen. Ergebnisse landen wieder an der Task, sodass die Liste die Single-Source-of-Truth bleibt.
Architektur-Überblick
Ein Monorepo (C:\Private\ClaudeDo, gehostet auf git.kuns.dev), zwei Prozesse, gekoppelt über eine gemeinsame SQLite-Datenbank:
┌─────────────────────┐ ┌──────────────────────┐
│ UI (Avalonia .NET) │ │ Worker (Node/TS) │
│ MVVM, Dialogs, │◄──────►│ Claude Agent SDK │
│ Queue-View │ SQLite │ Queue-Polling │
└─────────────────────┘ WAL └──────────────────────┘
│ │
└─────── todo.db ───────────────┘
(~/.todo-app/todo.db)
- UI (
todo-app-ui, Avalonia MVVM): Listen & Tasks verwalten, Status ändern, Ergebnisse anzeigen. - Worker (
todo-app-worker, TypeScript): pollt die DB, arbeitetqueuedTasks ab, schreibt Ergebnisse zurück. - SQLite im WAL-Mode für sauberes concurrent read/write zwischen beiden Prozessen.
Datenmodell
Drei Tabellen in todo.db:
lists
id(TEXT, uuid),name(TEXT),tags(TEXT, JSON-Array),created_at
tasks
id(TEXT, uuid),list_id(FK),title,descriptiontags(JSON-Array, überschreibt/ergänzt List-Tags)status:manual|queued|running|done|failedpriority:normal|override(→ läuft parallel zur Queue)scheduled_for(TIMESTAMP, nullable — "nicht vor")result(TEXT, Markdown),log_path(TEXT, Pfad zur Session-Log-Datei)created_at,started_at,finished_at
worker_state
id(1),last_heartbeat,active_queue_task_id,active_override_task_id- Dient UI als Signal, ob Worker läuft und welche Task aktiv ist.
Tag-Modell (Startset)
- Liste hat Default-Tags, Task erbt und kann ergänzen/überschreiben.
- Minimal-Startset:
manual→ Worker ignoriert, reine Notiz/Checkliste.agent→ Worker pickt auf, wenn Statusqueued.
- Weitere Profile (
code,research…) später als zusätzliche Tags + Handler im Worker.
Queue-Semantik
- Default: Tasks mit Tag
agentund Statusqueuedwerden sequenziell abgearbeitet (FIFO, nachcreated_at). - Schedule:
scheduled_forgesetzt → Worker überspringt, bis Zeit erreicht. - Override: UI-Button "Jetzt ausführen" setzt
priority = override. Worker startet parallel zur laufenden Queue-Task. Max. 1 Queue + 1 Override = 2 gleichzeitige Runs. - Ein zweites Override während ein Override läuft → Meldung "Override bereits aktiv".
Worker-Komponenten (TypeScript)
db.ts— better-sqlite3, Prepared Statements, WAL-Mode aktivieren.poller.ts— alle 5s: nächstequeuedTask auswählen (Tagagent,scheduled_for≤ jetzt, kein anderer Queue-Run aktiv), sowie pendingoverride.runner.ts— startet Agent-SDK-Run, streamt Messages in Log-Datei, speichert Ergebnis.- Input: Task-Titel + Description als User-Prompt.
- Standard-Toolset: Read/Write in
~/.todo-app/sandbox/<task-id>/, keine Netzwerk-Tools by default (später per Tag erweiterbar).
state.ts— schreibt Heartbeat alle 5s inworker_state(UI erkennt so, ob Worker läuft).- Konfig via
~/.todo-app/worker.config.json:ANTHROPIC_API_KEY,model,sandbox_root,poll_interval_ms.
UI-Komponenten (Avalonia)
- MainWindow mit 2-Pane-Layout: links Listen, rechts Tasks der gewählten Liste.
- TaskItemView zeigt Titel, Tags, Status (Badge), "Run Now"-Button (→ setzt
override). - TaskDetailPane — erweiterbare Ansicht mit Description, Result-Markdown (AvaloniaEdit oder Markdown.Avalonia), Link zum Log.
- StatusBar — zeigt Worker-Status aus
worker_state.last_heartbeat(< 15s = online). - SettingsDialog — Default-Tags, Poll-Interval, Pfad zur todo.db.
Zugriff auf DB via Microsoft.Data.Sqlite + schmaler Repository-Layer (TaskRepository, ListRepository). MVVM via CommunityToolkit.Mvvm.
Project-Layout (Monorepo)
Repo: ClaudeDo auf git.kuns.dev, lokal C:\Private\ClaudeDo
/ClaudeDo
/ui Avalonia .NET 8
ClaudeDo.sln
/src
/ClaudeDo.App App.axaml, Program.cs (Entry)
/ClaudeDo.Ui Views, ViewModels
/ClaudeDo.Data Repositories, Models, SqliteConnectionFactory
/tests
/worker TypeScript / Node
/src
db.ts, poller.ts, runner.ts, state.ts, config.ts, index.ts
/logs runtime, gitignored
package.json, tsconfig.json
/schema
schema.sql Single source of truth für DB-Schema
migrations/ (später, falls nötig)
/docs
README.md, architecture.md
.gitignore bin/, obj/, node_modules/, logs/, *.db, worker.config.json
Vorteil Monorepo: gemeinsames schema.sql, atomische Änderungen über UI+Worker, ein Clone reicht.
Verification
- Schema-Init: Worker erstellt
todo.dbbei erstem Start mit WAL, legt Tabellen an. →sqlite3 todo.db ".schema"zeigt erwartete Tabellen. - End-to-End Happy Path:
- UI: Liste "Test" anlegen, Task mit Tag
agent+ Statusqueuederzeugen, description: "Schreibe eine Haiku über Intralogistik". - Worker erkennt Task binnen 5s (Log:
picked up task <id>), startet Agent-Run, schreibt Result zurück. - UI zeigt Status
done+ Result-Markdown nach Reload/Refresh.
- UI: Liste "Test" anlegen, Task mit Tag
- Override-Parallelität: Zwei
queuedTasks anlegen → nur eine läuft. Bei zweiter "Run Now" klicken → beide laufen parallel,worker_statezeigt beide IDs. - Schedule: Task mit
scheduled_for = now + 2min→ Worker wartet; nach Ablauf startet sie. - Worker-Offline-Erkennung: Worker-Prozess killen → UI-StatusBar wechselt innerhalb 15s auf "offline".
- Unit-Tests (Worker):
pollerSelection-Logik (Priorität Override, Schedule-Filter, Sequenzialität) mit In-Memory-SQLite.
Offene Punkte für später (nicht Scope dieses Plans)
- Zusätzliche Tag-Profile mit spezialisierten Toolsets (
code→ Bash/Git-Tools,research→ WebFetch). - MCP-Server-Integration für externe Dienste.
- Notification bei Task-fertig (Windows Toast).
- Encrypted API-Key-Storage (erstmal Plaintext-JSON mit User-File-ACL).