# Daily Prep — Live Output View + Clear Day — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Stream the daily-prep run's output into a live, human-readable view (a new mode in the Details island), and add a "Clear Day" button that empties MyDay.

**Architecture:** The worker broadcasts `PrepStarted/PrepLine/PrepFinished` over SignalR (mirroring `TaskStarted/TaskMessage/TaskFinished`). `PrimeRunner` forwards each Claude stdout line instead of discarding it. The UI `WorkerClient` re-raises these as events; `DetailsIslandViewModel` gains a `PrepLog` + `IsPrepMode` panel rendered with the existing terminal renderer. A `ClearMyDay` hub method bulk-clears `IsMyDay`. MyDay header gets "Vorbereitungs-Log" and "Tag leeren" buttons.

**Tech Stack:** .NET 8, ASP.NET Core SignalR, EF Core (SQLite), Avalonia + CommunityToolkit.Mvvm, xUnit.

**Spec:** `docs/superpowers/specs/2026-06-03-daily-prep-live-view-design.md`

---

## Build & test commands

`.slnx` needs .NET 9; build/test individual csproj with `-c Release` (a running Worker may lock Debug).

```bash
dotnet build src/ClaudeDo.Worker/ClaudeDo.Worker.csproj -c Release
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
```

UI cannot be GUI-smoke-tested headlessly — note that explicitly where it applies; the human verifies visuals.

## Reference anchors (verify before editing — line numbers drift)

- `src/ClaudeDo.Worker/Prime/Interfaces/IPrimeBroadcaster.cs` — currently only `PrimeFiredAsync`.
- `src/ClaudeDo.Worker/Hub/HubBroadcaster.cs:13-57` — broadcast methods; `PrimeFired` at ~52-56.
- `src/ClaudeDo.Worker/Prime/PrimeRunner.cs:31-79` — `FireAsync`; discard lambda at ~55-60; ctor at ~19-29.
- `src/ClaudeDo.Worker/Hub/WorkerHub.cs:542-549` — `RunDailyPrepNow` (uses `_broadcaster`); DailyNote CRUD at 559-583 (shows the db-context pattern this hub uses).
- `src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs:19` — `TaskMessageEvent`; `:55` — `RunDailyPrepNowAsync`.
- `src/ClaudeDo.Ui/Services/WorkerClient.cs:99-122` — `TaskStarted/Finished/Message` hub.On; `:170-173` — `PrimeFired` hub.On (the pattern to copy).
- `src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs` — `IsNotesMode` ~56, `Log` ~193, ctor/subscriptions ~272-337, `OnTaskMessage` ~339-363 (stdout→`StreamLineFormatter`→`Log`), `ShowNotes` ~478-483.
- `src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml:131-302` — body grid; task panel `IsVisible="{Binding !IsNotesMode}"`, notes panel `IsVisible="{Binding IsNotesMode}"`; `SessionTerminalView` embedded ~295.
- `src/ClaudeDo.Ui/Views/Islands/SessionTerminalView.axaml:54-75` — `ItemsControl ItemsSource="{Binding Log}"` + the `LogLineViewModel` item template to reuse.
- `src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs` — `NotesRequested` ~29, `OpenNotesCommand`+`PrepareDayCommand` ~33-45, `ShowNotesRow`/`IsMyDayList` ~65-66, both set in `LoadForList` ~212-213.
- `src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml:69-84` — Notes + PrepareDay buttons (styling to copy).
- `src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs:199-201` — island event wiring; `:225` — `PrimeFired` subscription.
- Fakes to keep in sync: `tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs`, `tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs` (`FakeWorkerClient`).

---

## Task 1: Worker — prep output broadcast + streaming

**Files:**
- Modify: `src/ClaudeDo.Worker/Prime/Interfaces/IPrimeBroadcaster.cs`
- Modify: `src/ClaudeDo.Worker/Hub/HubBroadcaster.cs`
- Modify: `src/ClaudeDo.Worker/Prime/PrimeRunner.cs`
- Test: `tests/ClaudeDo.Worker.Tests/Prime/PrimeRunnerTests.cs`

- [ ] **Step 1: Write the failing test.** Extend `PrimeRunnerTests` with a fake `IPrimeBroadcaster` that records calls. The fake `IClaudeProcess` should invoke `onStdoutLine` with two sample lines and return `RunResult { ExitCode = 0, ResultMarkdown = "ok" }`.

```csharp
[Fact]
public async Task FireAsync_streams_started_lines_and_finished()
{
    var broadcaster = new RecordingPrimeBroadcaster();
    var claude = new FakeClaudeProcess(emitLines: new[] { "{\"a\":1}", "{\"b\":2}" }, exitCode: 0, result: "ok");
    var runner = NewRunner(claude, broadcaster); // build with temp-sqlite dbFactory + fake clock + logger + broadcaster
    var schedule = new PrimeScheduleDto(Guid.Empty, 0, TimeSpan.Zero, true, null, null);

    var outcome = await runner.FireAsync(schedule, CancellationToken.None);

    Assert.True(outcome.Success);
    Assert.Equal(1, broadcaster.StartedCount);
    Assert.Equal(new[] { "{\"a\":1}", "{\"b\":2}" }, broadcaster.Lines);
    Assert.Single(broadcaster.FinishedResults);
    Assert.True(broadcaster.FinishedResults[0]);
}
```

`RecordingPrimeBroadcaster` implements `IPrimeBroadcaster`: `StartedCount`, `List<string> Lines`, `List<bool> FinishedResults`, and a no-op `PrimeFiredAsync`. If the existing `FakeClaudeProcess` cannot emit lines, add an optional `emitLines` parameter that loops `await onStdoutLine(line)` before returning.

- [ ] **Step 2: Run — expect FAIL** (interface methods + ctor param missing).

```bash
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release --filter PrimeRunner
```

- [ ] **Step 3: Extend `IPrimeBroadcaster`:**

```csharp
public interface IPrimeBroadcaster
{
    Task PrimeFiredAsync(Guid scheduleId, bool success, string message, DateTimeOffset firedAt);
    Task PrepStartedAsync();
    Task PrepLineAsync(string line);
    Task PrepFinishedAsync(bool success);
}
```

(Keep the existing `PrimeFiredAsync` signature exactly as it is in the current file.)

- [ ] **Step 4: Implement in `HubBroadcaster`** (add next to `PrimeFired`):

```csharp
    public Task PrepStarted() => _hub.Clients.All.SendAsync("PrepStarted");
    public Task PrepLine(string line) => _hub.Clients.All.SendAsync("PrepLine", line);
    public Task PrepFinished(bool success) => _hub.Clients.All.SendAsync("PrepFinished", success);

    Task IPrimeBroadcaster.PrepStartedAsync() => PrepStarted();
    Task IPrimeBroadcaster.PrepLineAsync(string line) => PrepLine(line);
    Task IPrimeBroadcaster.PrepFinishedAsync(bool success) => PrepFinished(success);
```

(Match the existing explicit-interface style used for `PrimeFiredAsync`.)

- [ ] **Step 5: Wire `PrimeRunner`.** Add `IPrimeBroadcaster _broadcaster` as a ctor param (and field). Rewrite the body of `FireAsync` after the gate check to:

```csharp
        if (!await _gate.WaitAsync(0, ct))
            return new PrimeRunOutcome(false, "Daily prep already running");

        var success = false;
        try
        {
            await _broadcaster.PrepStartedAsync();

            var cwd = Paths.AppDataRoot();
            Directory.CreateDirectory(cwd);

            int maxTasks;
            await using (var dbCtx = await _dbFactory.CreateDbContextAsync(ct))
            {
                var settings = await new AppSettingsRepository(dbCtx).GetAsync(ct);
                maxTasks = settings.DailyPrepMaxTasks < 1 ? 1 : settings.DailyPrepMaxTasks;
            }

            var today = DateOnly.FromDateTime(_clock.Now.LocalDateTime);
            var prompt = DailyPrepPrompt.BuildPrompt(maxTasks, today);
            var args = DailyPrepPrompt.BuildArgs(MaxTurns);

            using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
            timeoutCts.CancelAfter(FireTimeout);

            var result = await _claude.RunAsync(
                arguments: args,
                prompt: prompt,
                workingDirectory: cwd,
                onStdoutLine: line => _broadcaster.PrepLineAsync(line),
                ct: timeoutCts.Token);

            success = result.IsSuccess;
            return success
                ? new PrimeRunOutcome(true, "Daily prep complete")
                : new PrimeRunOutcome(false, $"exit code {result.ExitCode}");
        }
        catch (OperationCanceledException) when (!ct.IsCancellationRequested)
        {
            return new PrimeRunOutcome(false, $"timed out after {FireTimeout.TotalMinutes:0} min");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Daily prep run failed");
            return new PrimeRunOutcome(false, ex.Message);
        }
        finally
        {
            await _broadcaster.PrepFinishedAsync(success);
            _gate.Release();
        }
```

DI is unchanged: `AddSingleton<IPrimeRunner, PrimeRunner>()` resolves `IPrimeBroadcaster` (registered as `sp => sp.GetRequiredService<HubBroadcaster>()`).

- [ ] **Step 6: Update existing `PrimeRunnerTests` ctor calls** to pass the recording broadcaster; build + run.

```bash
dotnet build src/ClaudeDo.Worker/ClaudeDo.Worker.csproj -c Release
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release --filter PrimeRunner
```

- [ ] **Step 7: Commit.**

```bash
git add src/ClaudeDo.Worker/Prime src/ClaudeDo.Worker/Hub/HubBroadcaster.cs tests/ClaudeDo.Worker.Tests/Prime
git commit -m "feat(daily-prep): stream prep output via PrepStarted/PrepLine/PrepFinished"
```

---

## Task 2: Worker — `ClearMyDay` hub method

**Files:**
- Modify: `src/ClaudeDo.Worker/Hub/WorkerHub.cs`
- Test: a new/existing hub test under `tests/ClaudeDo.Worker.Tests/Hub/` (mirror an existing hub test that seeds a real SQLite db and constructs `WorkerHub`)

- [ ] **Step 1: Write the failing test.** Seed three tasks: two with `IsMyDay=true` (one Idle, one Done), one with `IsMyDay=false`. Construct `WorkerHub` the way existing hub tests do (the same `null!` argument list, plus a recording `HubBroadcaster`/clients). Call `ClearMyDay()`; assert both MyDay rows are now `false`, the third is untouched, and the returned count is 2.

```csharp
[Fact]
public async Task ClearMyDay_clears_all_isMyDay_tasks()
{
    // seed via the test's db helper ...
    var hub = NewHub(/* ... */);
    var cleared = await hub.ClearMyDay();

    Assert.Equal(2, cleared);
    await using var ctx = NewContext();
    Assert.False(await ctx.Tasks.AnyAsync(t => t.IsMyDay));
}
```

- [ ] **Step 2: Run — expect FAIL.**

- [ ] **Step 3: Add the method** to `WorkerHub` (use the same db-context acquisition the neighbouring hub methods use — e.g. `_dbFactory`/repository field name found in the file — and the existing `_broadcaster` field):

```csharp
public async Task<int> ClearMyDay()
{
    await using var ctx = await _dbFactory.CreateDbContextAsync();
    var ids = await ctx.Tasks.Where(t => t.IsMyDay).Select(t => t.Id).ToListAsync();
    if (ids.Count == 0) return 0;

    await ctx.Tasks.Where(t => t.IsMyDay)
        .ExecuteUpdateAsync(s => s.SetProperty(t => t.IsMyDay, false));

    foreach (var id in ids)
        await _broadcaster.TaskUpdated(id);

    return ids.Count;
}
```

If `WorkerHub` does not already have an `IDbContextFactory<ClaudeDoDbContext>` field, use whatever data-access dependency the other hub methods use (read the file). Do NOT add a new ctor param unless unavoidable (it would break hub-test fakes — if you must, update all `new WorkerHub(...)` call sites).

- [ ] **Step 4: Run — expect PASS.** Build Worker.

- [ ] **Step 5: Commit.**

```bash
git add src/ClaudeDo.Worker/Hub/WorkerHub.cs tests/ClaudeDo.Worker.Tests/Hub
git commit -m "feat(daily-prep): add ClearMyDay hub method"
```

---

## Task 3: UI — WorkerClient prep events + ClearMyDayAsync

**Files:**
- Modify: `src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs`
- Modify: `src/ClaudeDo.Ui/Services/WorkerClient.cs`
- Modify fakes: `tests/ClaudeDo.Ui.Tests/StubWorkerClient.cs`, `tests/ClaudeDo.Worker.Tests/UiVm/TasksIslandViewModelPlanningTests.cs` (FakeWorkerClient)

- [ ] **Step 1: Declare on `IWorkerClient`** (near `TaskMessageEvent` / `RunDailyPrepNowAsync`):

```csharp
event Action? PrepStartedEvent;
event Action<string>? PrepLineEvent;
event Action<bool>? PrepFinishedEvent;
Task ClearMyDayAsync();
```

- [ ] **Step 2: Implement in `WorkerClient`.** Add the events; register hub callbacks mirroring the `PrimeFired` registration (~line 170):

```csharp
public event Action? PrepStartedEvent;
public event Action<string>? PrepLineEvent;
public event Action<bool>? PrepFinishedEvent;

// in the hub-wiring section:
_hub.On("PrepStarted", () => Dispatcher.UIThread.Post(() => PrepStartedEvent?.Invoke()));
_hub.On<string>("PrepLine", line => Dispatcher.UIThread.Post(() => PrepLineEvent?.Invoke(line)));
_hub.On<bool>("PrepFinished", ok => Dispatcher.UIThread.Post(() => PrepFinishedEvent?.Invoke(ok)));

public Task ClearMyDayAsync() => _connection.InvokeAsync("ClearMyDay");
```

(Use the exact connection field name and async-call style of neighbouring methods like `RunDailyPrepNowAsync` / `GenerateWeekReport`. `ClearMyDay` returns `int` on the hub; invoking it as a void `InvokeAsync("ClearMyDay")` is fine, or `InvokeAsync<int>` if you want the count.)

- [ ] **Step 3: Update the fakes.** Add the three events (as `public event …` auto-implemented) and `ClearMyDayAsync() => Task.CompletedTask` to both `StubWorkerClient` and `FakeWorkerClient`. For the ClearDay command test (Task 5), give `StubWorkerClient` a `ClearMyDayCalls` counter incremented in `ClearMyDayAsync`.

- [ ] **Step 4: Build App + both test projects; fix any remaining fake gaps.**

```bash
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release
```

- [ ] **Step 5: Commit.**

```bash
git add src/ClaudeDo.Ui/Services tests
git commit -m "feat(daily-prep): expose prep stream events and ClearMyDay on the UI worker client"
```

---

## Task 4: UI — Details island prep mode + live log

**Files:**
- Modify: `src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs`
- Modify: `src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml`
- Test: `tests/ClaudeDo.Ui.Tests/...DetailsIslandViewModel...` (mirror existing Details VM tests; if none, add a small test file)

- [ ] **Step 1: Write the failing test.** Construct `DetailsIslandViewModel` with a `StubWorkerClient` (mirror existing construction). Then:

```csharp
[Fact]
public void PrepLine_event_appends_to_PrepLog()
{
    var stub = new StubWorkerClient();
    var vm = NewDetailsVm(stub);

    stub.RaisePrepLine("{\"type\":\"assistant\",\"text\":\"hi\"}"); // helper that invokes PrepLineEvent
    Assert.NotEmpty(vm.PrepLog);
}

[Fact]
public void ShowPrep_sets_prep_mode_and_clears_notes_mode()
{
    var vm = NewDetailsVm(new StubWorkerClient());
    vm.ShowPrep();
    Assert.True(vm.IsPrepMode);
    Assert.False(vm.IsNotesMode);
}
```

Add `RaisePrepStarted/RaisePrepLine/RaisePrepFinished` helpers to `StubWorkerClient` that invoke the corresponding events.

- [ ] **Step 2: Run — expect FAIL.**

- [ ] **Step 3: Implement in `DetailsIslandViewModel`:**
  - Add `[ObservableProperty] private bool _isPrepMode;` and `[ObservableProperty] private bool _isPrepRunning;`.
  - Add `public ObservableCollection<LogLineViewModel> PrepLog { get; } = new();`.
  - In the ctor, subscribe: `_worker.PrepStartedEvent += OnPrepStarted; _worker.PrepLineEvent += OnPrepLine; _worker.PrepFinishedEvent += OnPrepFinished;` (guard with the same `_worker is not null` pattern used for other events).
  - Handlers:

```csharp
private void OnPrepStarted()
{
    PrepLog.Clear();
    IsPrepRunning = true;
}

private void OnPrepLine(string line) => AppendStdoutLine(PrepLog, line);

private void OnPrepFinished(bool success) => IsPrepRunning = false;
```

  - Factor the stdout-formatting currently inside `OnTaskMessage` into a reusable
    `private void AppendStdoutLine(ObservableCollection<LogLineViewModel> target, string line)`
    that runs the line through `StreamLineFormatter` and appends `LogLineViewModel`(s).
    Have `OnTaskMessage`'s stdout branch call `AppendStdoutLine(Log, strippedLine)` so both
    paths share one implementation. (Events arrive already on the UI thread via
    `Dispatcher.UIThread.Post` in `WorkerClient`, so direct collection mutation is correct.)
  - Add `public void ShowPrep()` mirroring `ShowNotes()`: call `Bind(null)`, set
    `IsNotesMode = false`, `IsPrepMode = true`.
  - In `ShowNotes()` add `IsPrepMode = false`. In `Bind(...)` reset both `IsNotesMode` and
    `IsPrepMode` to false (find where `IsNotesMode` is reset; add `IsPrepMode` beside it).

- [ ] **Step 4: Update `DetailsIslandView.axaml`.**
  - Change the task-details panel visibility from `IsVisible="{Binding !IsNotesMode}"` to a
    converter-free multi-condition. Avalonia lacks `&&` in bindings, so add a computed
    property `public bool IsTaskDetailVisible => !IsNotesMode && !IsPrepMode;` to the VM
    (raise its change notification from the `OnIsNotesModeChanged`/`OnIsPrepModeChanged`
    partial methods generated by `[ObservableProperty]`) and bind the task panel to
    `IsVisible="{Binding IsTaskDetailVisible}"`.
  - Add a third panel after the notes panel:

```xml
<Panel IsVisible="{Binding IsPrepMode}">
    <DockPanel>
        <TextBlock DockPanel.Dock="Top" Margin="16,12"
                   Text="{loc:Tr details.prepTitle}" Classes="h2"/>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding PrepLog}"/>
        </ScrollViewer>
    </DockPanel>
</Panel>
```

  The `ItemsControl` reuses the implicit `LogLineViewModel` `DataTemplate` that
  `SessionTerminalView` relies on. If that template is defined locally inside
  `SessionTerminalView.axaml` (not in a shared resource), either move it to a shared
  `ResourceDictionary` (e.g. App resources) and reference it from both, or set the
  `ItemsControl.ItemTemplate` to a copy of that template. Prefer sharing over copying.
  Add `details.prepTitle` ("Daily prep" / "Tagesvorbereitung") to both locale json files.

- [ ] **Step 5: Run UI tests — expect PASS; build App.**

```bash
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
```

- [ ] **Step 6: Commit.**

```bash
git add src/ClaudeDo.Ui src/ClaudeDo.Localization tests/ClaudeDo.Ui.Tests
git commit -m "feat(daily-prep): add live prep-output mode to the Details island"
```

---

## Task 5: UI — MyDay buttons + shell wiring

**Files:**
- Modify: `src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs`
- Modify: `src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml`
- Modify: `src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs`
- Modify: `src/ClaudeDo.Localization/locales/en.json`, `de.json`
- Test: `tests/ClaudeDo.Worker.Tests/UiVm/...` or `tests/ClaudeDo.Ui.Tests/...` (TasksIslandViewModel)

- [ ] **Step 1: Write the failing tests.**

```csharp
[Fact]
public async Task ClearDayCommand_calls_worker()
{
    var stub = new StubWorkerClient();
    var vm = NewTasksVm(stub);
    await vm.ClearDayCommand.ExecuteAsync(null);
    Assert.Equal(1, stub.ClearMyDayCalls);
}

[Fact]
public async Task PrepareDayCommand_raises_PrepRequested()
{
    var vm = NewTasksVm(new StubWorkerClient());
    var raised = false;
    vm.PrepRequested += () => raised = true;
    await vm.PrepareDayCommand.ExecuteAsync(null);
    Assert.True(raised);
}
```

- [ ] **Step 2: Run — expect FAIL.**

- [ ] **Step 3: Implement in `TasksIslandViewModel`:**
  - Add `public event Action? PrepRequested;` next to `NotesRequested`.
  - In `PrepareDayAsync` (the existing `[RelayCommand]`), raise `PrepRequested?.Invoke();`
    in addition to the existing `RunDailyPrepNowAsync()` call.
  - Add:

```csharp
[RelayCommand]
private void ShowPrepLog() => PrepRequested?.Invoke();

[RelayCommand]
private async Task ClearDayAsync()
{
    if (_worker is null) return;
    try { await _worker.ClearMyDayAsync(); }
    catch { /* worker offline; broadcast will reconcile on return */ }
}
```

- [ ] **Step 4: Add the two buttons** to the MyDay header in `TasksIslandView.axaml`,
  immediately after the existing "Prepare day" button (~line 84), copying its styling
  (`DockPanel.Dock="Top" Classes="btn" HorizontalAlignment="Stretch"
  HorizontalContentAlignment="Left" Margin="16,0,16,8" IsVisible="{Binding IsMyDayList}"`):

```xml
<Button DockPanel.Dock="Top" Classes="btn" HorizontalAlignment="Stretch"
        HorizontalContentAlignment="Left" Margin="16,0,16,8"
        IsVisible="{Binding IsMyDayList}"
        Command="{Binding ShowPrepLogCommand}"
        Content="{loc:Tr tasks.prepLog}"/>
<Button DockPanel.Dock="Top" Classes="btn" HorizontalAlignment="Stretch"
        HorizontalContentAlignment="Left" Margin="16,0,16,8"
        IsVisible="{Binding IsMyDayList}"
        Command="{Binding ClearDayCommand}"
        Content="{loc:Tr tasks.clearDay}"/>
```

  Add `tasks.prepLog` (en "Prep log" / de "Vorbereitungs-Log") and `tasks.clearDay`
  (en "Clear day" / de "Tag leeren") to both locale json files.

- [ ] **Step 5: Wire the shell.** In `IslandsShellViewModel` where `Tasks.NotesRequested`
  is wired (~line 201), add:

```csharp
Tasks.PrepRequested += () => Details.ShowPrep();
```

- [ ] **Step 6: Run tests + build App.**

```bash
dotnet test tests/ClaudeDo.Ui.Tests/ClaudeDo.Ui.Tests.csproj -c Release
dotnet test tests/ClaudeDo.Worker.Tests/ClaudeDo.Worker.Tests.csproj -c Release
dotnet build src/ClaudeDo.App/ClaudeDo.App.csproj -c Release
```

- [ ] **Step 7: Manual smoke (human, not headless):** start Worker + App, open MyDay, click
  "Tag vorbereiten" → Details island opens in prep mode and streams readable lines; click
  "Tag leeren" → MyDay empties; after a scheduled run, "Vorbereitungs-Log" opens the filled
  log. Confirm the three buttons only appear on MyDay.

- [ ] **Step 8: Commit.**

```bash
git add src/ClaudeDo.Ui src/ClaudeDo.Localization tests
git commit -m "feat(daily-prep): add Prep-log and Clear-day buttons to MyDay header"
```

---

## Final verification

- [ ] Build Worker + App (Release).
- [ ] `dotnet test` Worker.Tests, Ui.Tests, Localization.Tests — all green.
- [ ] Manual: prep streams live into the Details island (manual opens it; scheduled fills it silently, opened via the button); Clear Day empties MyDay immediately.

## Notes / risks

- Mode flags `IsNotesMode` / `IsPrepMode` are mutually exclusive; the task-details panel
  uses the computed `IsTaskDetailVisible`. Verify all three modes switch cleanly.
- Reusing the `LogLineViewModel` template: prefer promoting it to a shared resource over
  copying, to avoid drift between the session terminal and the prep log.
- `ClearMyDay` broadcasts one `TaskUpdated` per affected id; MyDay is small (capped), so
  this is fine.
- Keep `PrimeRunner`'s "already running" early-return emitting no prep events.
