Files
ClaudeDo/CLAUDE.md
T

7.8 KiB
Raw Blame History

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.json and 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 through WaitingForChildren first. 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 (with BlockedByTaskId 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:

  1. 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.
  2. Write it down — a spec in docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md and a step-by-step plan in docs/superpowers/plans/ (superpowers:writing-plans). Commit the docs.
  3. 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.
  4. Trust but verify — read each subagent's diff and run the build/tests yourself before marking a task done.
  5. Bugs → superpowers:systematic-debugging (find the root cause before any fix).
  6. 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 --filter scoped 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 sonnet model; stage files explicitly by path — never git add -A (parallel sessions often leave unrelated WIP in the tree).
  • Icons: Material Design Icons via mdi:Name + the IconKey converter (a misspelled name silently renders nothing — MdiIconNamesTests guards it). Colour comes from the ICON PAINTING block in IslandStyles.axaml (class + state); setting Foreground/Stroke inline kills the hover state.
  • Localization: locales/en.json and locales/de.json keys 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 release
  • docs/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. See docs/explore-notes/README.md. Current notes: worker-task-pipeline, usage-monitoring, external-mcp, review-merge, conpty-sessions, installer-preflight.