# Daily Prep — Live Output View + Clear Day — Design Date: 2026-06-03 ## Overview Two follow-ups to the daily-prep ("Prime Claude") feature: 1. **Live output view.** While Claude prepares the day, there is no feedback. Add a live, human-readable view of the prep run's output, shown as a new content mode in the existing right-hand **Details island** (mirroring how Daily Notes works — a mode swap, not a separate window/column). 2. **Clear Day button.** A MyDay-header button that clears the MyDay selection immediately. ## Goals - See the prep run's progress live, rendered with the same friendly terminal renderer used for task runs (assistant text + tool calls like `set_my_day …`, not raw NDJSON). - Both manual (button) and scheduled prep runs stream into the log. - The manual button opens the prep view; a scheduled run fills the log silently and is opened via a dedicated "Vorbereitungs-Log" button (the existing `PrimeStatus` footer remains the hint that a run happened). - A "Tag leeren" button clears all MyDay tasks (any status) with no confirmation. ## Non-Goals - No new island/column and no popup/overlay — reuse the Details island as a mode swap. - No persistence of prep output across app restarts (in-memory log only). - No undo for Clear Day (re-runnable via "Tag vorbereiten"). ## Key Decisions | Topic | Decision | | --- | --- | | Rendering | Reuse the existing `SessionTerminalView` / `StreamLineFormatter` renderer. | | Location | New `IsPrepMode` content panel inside the Details island (like `IsNotesMode`). | | Lifecycle | Manual click opens the view (UI-local); `PrepStarted/PrepLine/PrepFinished` events fill the log regardless of current mode; scheduled runs do not auto-open. | | Open after schedule | Dedicated "Vorbereitungs-Log" header button + existing `PrimeStatus` footer hint. | | Clear Day scope | All MyDay tasks regardless of status. | | Clear Day confirm | None — clear directly. | ## Architecture ### Feature A — Live prep output **Worker** - Extend `IPrimeBroadcaster` (`src/ClaudeDo.Worker/Prime/Interfaces/IPrimeBroadcaster.cs`) with `PrepStartedAsync()`, `PrepLineAsync(string line)`, `PrepFinishedAsync(bool success)`. - Implement in `HubBroadcaster` (`src/ClaudeDo.Worker/Hub/HubBroadcaster.cs`) sending SignalR events `PrepStarted`, `PrepLine` (string), `PrepFinished` (bool). - `PrimeRunner` (`src/ClaudeDo.Worker/Prime/PrimeRunner.cs`): inject `IPrimeBroadcaster`. In `FireAsync`, after the single-flight gate is entered and a run will actually happen: call `PrepStartedAsync()` before `RunAsync`; replace the discard lambda with `async line => await _broadcaster.PrepLineAsync(line)`; call `PrepFinishedAsync(result.IsSuccess)` after. The "already running" early-return path emits nothing (no run occurs). Both scheduled and manual runs go through `FireAsync`, so both stream. **UI** - `WorkerClient` (`src/ClaudeDo.Ui/Services/WorkerClient.cs`): register `_hub.On<…>("PrepStarted"/"PrepLine"/"PrepFinished", …)` each via `Dispatcher.UIThread.Post`, raising `PrepStartedEvent` / `PrepLineEvent(string)` / `PrepFinishedEvent(bool)`. Declare these on `IWorkerClient`. - `DetailsIslandViewModel`: add `IsPrepMode` (bool), `IsPrepRunning` (bool), a dedicated `PrepLog` (`ObservableCollection`), and `ShowPrep()` (calls `Bind(null)`, sets `IsNotesMode=false`, `IsPrepMode=true`). Subscribe to the three prep events in the ctor (always active, independent of mode): - `PrepStarted` → clear `PrepLog`, `IsPrepRunning=true`. - `PrepLine` → format the line with the same `StreamLineFormatter` path used by the stdout branch of `OnTaskMessage`, append a `LogLineViewModel` to `PrepLog`. - `PrepFinished` → `IsPrepRunning=false` (optionally append a status line). Mode exclusivity: the normal task-details panel becomes visible on `!IsNotesMode && !IsPrepMode`; `ShowNotes()` also sets `IsPrepMode=false`; `Bind(task)` resets both flags. - `DetailsIslandView.axaml`: add a third `` in the body grid alongside the existing details/notes panels, rendering `PrepLog` in the terminal style (reuse the `LogLineViewModel` item template used by `SessionTerminalView`). **Wiring** - `TasksIslandViewModel`: add a `PrepRequested` event (mirror `NotesRequested`). `PrepareDayCommand` raises `PrepRequested` in addition to calling `RunDailyPrepNowAsync()`. Add `ShowPrepLogCommand` that raises `PrepRequested`. Add the "Vorbereitungs-Log" button to the MyDay header (`IsVisible="{Binding IsMyDayList}"`). - `IslandsShellViewModel`: wire `Tasks.PrepRequested += () => Details.ShowPrep()`. ### Feature B — Clear Day **Worker** - `WorkerHub.ClearMyDay()` (`src/ClaudeDo.Worker/Hub/WorkerHub.cs`): query ids where `IsMyDay == true`; `ExecuteUpdateAsync` setting `is_my_day = false`; broadcast `TaskUpdated(id)` for each affected id (the UI reloads the current list on `TaskUpdated`). **UI** - `IWorkerClient.ClearMyDayAsync()` + `WorkerClient` impl invoking `"ClearMyDay"`. - `TasksIslandViewModel.ClearDayCommand` calls `_worker.ClearMyDayAsync()` (no confirm). Add the "Tag leeren" button to the MyDay header next to "Tag vorbereiten". ## Data Flow (live view) 1. Trigger (schedule or button) → `PrimeRunner.FireAsync`. 2. `PrepStartedAsync()` → SignalR `PrepStarted` → `WorkerClient.PrepStartedEvent` → `DetailsIslandViewModel` clears `PrepLog`, sets `IsPrepRunning`. 3. Each Claude stdout line → `PrepLineAsync(line)` → `PrepLine` → formatted, appended to `PrepLog` (visible if the user is in prep mode; filled silently otherwise). 4. Run ends → `PrepFinishedAsync(success)` → `PrepFinished` → `IsPrepRunning=false`. 5. Manual button click also raised `PrepRequested` → `Details.ShowPrep()` (view open). After a scheduled run, the user clicks "Vorbereitungs-Log" to open it. ## Error Handling - Prep run fails/times out → `PrepFinished(false)`; the existing `PrimeFired` footer status still reports failure. - "Already running" → no prep events emitted (no run happened); existing behavior intact. - `ClearMyDay` with zero MyDay tasks → no-op, no broadcasts. ## Testing - Worker: `PrimeRunner` streams `PrepStarted` → N×`PrepLine` → `PrepFinished` (fake `IClaudeProcess` invokes `onStdoutLine` with sample lines; fake `IPrimeBroadcaster` records calls). `WorkerHub.ClearMyDay` clears all IsMyDay rows and broadcasts per id (real SQLite, mirror existing hub tests). - UI: `DetailsIslandViewModel` appends to `PrepLog` on `PrepLineEvent` and `ShowPrep()` sets the mode flags (mutual exclusivity with notes); `TasksIslandViewModel.ClearDayCommand` calls `ClearMyDayAsync` (stub worker client). ## Files (high level) **Modify** - `src/ClaudeDo.Worker/Prime/Interfaces/IPrimeBroadcaster.cs` - `src/ClaudeDo.Worker/Hub/HubBroadcaster.cs` - `src/ClaudeDo.Worker/Prime/PrimeRunner.cs` - `src/ClaudeDo.Worker/Hub/WorkerHub.cs` (ClearMyDay) - `src/ClaudeDo.Ui/Services/Interfaces/IWorkerClient.cs` - `src/ClaudeDo.Ui/Services/WorkerClient.cs` - `src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs` - `src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml` - `src/ClaudeDo.Ui/ViewModels/Islands/TasksIslandViewModel.cs` - `src/ClaudeDo.Ui/Views/Islands/TasksIslandView.axaml` - `src/ClaudeDo.Ui/ViewModels/IslandsShellViewModel.cs` - `src/ClaudeDo.Localization/locales/en.json`, `de.json` (button labels) **Test** - `tests/ClaudeDo.Worker.Tests/Prime/PrimeRunnerTests.cs` - `tests/ClaudeDo.Worker.Tests/Hub/…` (ClearMyDay) - `tests/ClaudeDo.Ui.Tests/…` (DetailsIslandViewModel prep events; TasksIslandViewModel ClearDay) + `StubWorkerClient` ## Known fragility Changing `IWorkerClient` / `WorkerClient` / VM constructors breaks hand-rolled fakes (`StubWorkerClient`, `FakeWorkerClient`) in both test projects — update all of them.