# 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<LogLineViewModel>`), 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 `<Panel IsVisible="{Binding IsPrepMode}">` 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.
