Die Build-Sektion hat bisher ein Rezept mit allen sechs Testprojekten vorgegeben; Implementer haben daraus "volle Suite vor fertig" gelesen. Bei bis zu 5 parallelen Tasks kostet das Stunden - und kann das nicht finden, wofuer es teuer ist: jeder Task arbeitet in seinem eigenen Worktree mit nur seiner eigenen Aenderung, eine Kollision zwischen zwei parallelen Tasks ist fuer beide unsichtbar. Kollisionen zeigen sich nach dem Merge, und genau dort laeuft verify_merges den Verify-Command einmal pro Batch. Neue Regel: Solution-Build immer (42s, faengt projektuebergreifende Compile-Brueche), Tests nur --no-build --filter auf das Beruehrte, und melden welcher Filter benutzt wurde. Die Messwerte stehen dabei, damit die Regel nicht als Geschmacksfrage gelesen wird. Messung 2026-09-02, sequenziell nach einem Build: Worker.Tests 507s, Ui 33s, Data 8s, Rest je 3s, Build 42s. Parallel ueber die Solution ist es schlechter, nicht besser (Worker 801s, Ui 82s) - diese Tests legen echte Git-Worktrees an und spawnen Prozesse, sie drangeln sich statt sich zu teilen. Ausserdem korrigiert: die Zeile "dotnet build ClaudeDo.slnx requires .NET 9" war veraltet.
7.8 KiB
ClaudeDo
A desktop task management app that executes tasks autonomously via Claude CLI in isolated git worktrees.
Architecture
Two-process system communicating over SignalR (127.0.0.1:47821):
- ClaudeDo.App — Avalonia desktop entry point, DI container setup
- ClaudeDo.Ui — Views, ViewModels, SignalR client (MVVM with CommunityToolkit.Mvvm)
- ClaudeDo.Data — SQLite data layer, repositories, models, GitService
- ClaudeDo.Worker — ASP.NET Core hosted service, task queue, Claude CLI runner
- ClaudeDo.Localization —
locales/en.json+locales/de.jsonand the lookup service - ClaudeDo.Releases — Gitea release client (
IReleaseClient), used by the Ui update check and the Installer - ClaudeDo.Installer — WPF (
UseWPF) setup app; install/update/uninstall step pipeline - tests/ — six xUnit projects (Worker, Data, Ui, Localization, Installer, Releases); Worker.Tests run real SQLite and real git
Per-project CLAUDE.md files exist for App, Data, Installer, Ui, Worker, and Worker.Tests —
those are the living per-project docs. Localization, Releases, and the other five test projects
have none; this file plus the code is all there is for them.
Tech Stack
- .NET 8.0, Avalonia 12.0.0 (Fluent theme)
- SQLite (WAL mode) via Entity Framework Core (Microsoft.EntityFrameworkCore.Sqlite)
- SignalR for real-time IPC
- CommunityToolkit.Mvvm (
[ObservableProperty],[RelayCommand]) - Git worktrees for task isolation
Key Paths
- DB:
~/.claudeDo/todo.db - UI config:
~/.claudeDo/ui.config.json - Worker config:
~/.claudeDo/worker.config.json - Logs:
~/.claudeDo/logs/ - Worktrees: configured per worker (sibling or central strategy)
Conventions
- Repository pattern — each entity has its own async repository
- All data operations are async with CancellationToken support
- EF Core migrations manage schema (Migrations/ folder in ClaudeDo.Data)
IDbContextFactory<ClaudeDoDbContext>used by singleton consumers (e.g. Worker)- Entity configuration via
IEntityTypeConfiguration<T>in Configuration/ folder - Task status flow:
Idle | Queued -> Running -> WaitingForReview -> Done | Failed | Cancelled; a task with children passes throughWaitingForChildrenfirst. Approve is the single review+merge action (no separate "Merge all"), and in the detail pane it's gated behind opening the diff. Full transition table →src/ClaudeDo.Worker/CLAUDE.md; merge/review/gate mechanics →docs/explore-notes/review-merge.md. - Worktree state flow: Active -> Merged | Discarded | Kept
- The queue picker claims tasks by
Status=Queued(withBlockedByTaskId IS NULL); the legacy tag system was removed - Interfaces live in an
Interfaces/subfolder beside their consumers (namespace unchanged) - Small single-consumer helper types live in their consumer's file, not standalone files
- Commit messages use conventional format:
{commitType}(slug): title - Views use compiled bindings (
x:DataType) - ViewModels use
[ObservableProperty]and[RelayCommand]source generators
Working style (autonomous)
For any non-trivial feature, bug, or change, run this loop without hand-holding:
- Brainstorm first (superpowers:brainstorming) — ask clarifying questions one at a time, propose 2–3 options with a recommendation, present a short design, get approval before building.
- Write it down — a spec in
docs/superpowers/specs/YYYY-MM-DD-<topic>-design.mdand a step-by-step plan indocs/superpowers/plans/(superpowers:writing-plans). Commit the docs. - Implement on main with superpowers:subagent-driven-development — one subagent per task, TDD, build + test, commit per task with Conventional Commits. Once the plan is approved, do NOT pause for re-approval between tasks; only stop for genuine decisions or blockers.
- Trust but verify — read each subagent's diff and run the build/tests yourself before marking a task done.
- Bugs → superpowers:systematic-debugging (find the root cause before any fix).
- Never claim UI works without running it — explicitly flag visual-verification gaps for the user to check.
Commit freely (per task + the spec/plan docs). Never push without asking.
Building & Testing
Build the whole solution, test only what you touched. Always -c Release — a running Worker locks the Debug output.
dotnet build ClaudeDo.slnx -c Release # ~40s, catches cross-project breaks
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release --no-build \
--filter "FullyQualifiedName~Handoff" # seconds, not minutes
.slnx needs SDK 9+ (this machine is on 10). On an older SDK build the projects individually:
src/ClaudeDo.App (pulls in Ui + Data) and src/ClaudeDo.Worker.
Do NOT run the full test suite to finish a task
Measured 2026-09-02, sequentially after one build: Worker.Tests 507s, Ui.Tests 33s, Data.Tests 8s, Localization/Installer/Releases 3s each, build 42s — ~10 min for all six. Run in parallel across projects it is worse, not better (Worker.Tests 801s, Ui.Tests 82s): these tests create real git worktrees and spawn processes, so they thrash rather than share.
With up to 5 implementer tasks running at once, a full suite per task costs hours — and cannot find
what it costs that for. Each task works in its own worktree containing only its own change, so a
collision between two parallel tasks is invisible to both. Collisions surface after the merge, which
is exactly where verify_merges runs the list's verify command once per batch. The full suite is
the merge gate's job, not the task's.
So, per task:
- Build: the whole solution, always. It's cheap and it catches the compile break your change caused three projects over.
- Tests:
--no-build --filterscoped to what you touched. Add a filter for the classes covering your change; if you genuinely can't scope it, run the one relevant test project, never all six. - Report what you ran and what you did not, so the merge session knows what is still unverified.
- Never report "all tests pass" when you ran a filtered subset. Say which filter you used.
Gotchas
- Subagents: use the
sonnetmodel; stage files explicitly by path — nevergit add -A(parallel sessions often leave unrelated WIP in the tree). - Icons:
PathIconfills its geometry — line-art icons must be filled geometry or aPath Classes="icon-stroke", else they render invisible. Colour comes from theICON PAINTINGblock inIslandStyles.axaml(class + state); settingForeground/Strokeinline kills the hover state. - Localization:
locales/en.jsonandlocales/de.jsonkeys must stay in parity (Localization.Tests enforces it). - Test fakes: changing
IWorkerClient/WorkerHub/ ViewModel constructors breaks hand-rolled fakes in both test projects — update them.
Docs
docs/open.md— open verification items and remaining code TODOs (the only doc kept current besides the CLAUDE.md files)docs/plan.md— original design spec (historical; tag-queue/schema.sql parts are outdated)docs/improvement-plan.md— improvement snapshot from 2026-04-13 (historical)docs/prompts-inventory.md,docs/mailbox-proposal.md— reference material (mailbox integration is parked)CHANGELOG.md— Keep a Changelog format, maintained on releasedocs/explore-notes/— distilled maps of complex subsystems (detail too fine for a CLAUDE.md, read on demand). Before deep-exploring a subsystem, check for a matching note first; after a deep explore, distill durable findings back and bump its "verified against" commit. Always verify against current code before trusting. Seedocs/explore-notes/README.md. Current notes:worker-task-pipeline,usage-monitoring,external-mcp,review-merge,conpty-sessions,installer-preflight.