## Context

mdreview currently reads markdown files once at startup. If a file changes on disk (edited by a writer, generated by CI, etc.), the reviewer must quit and restart to see updates. The anchor drift reconciliation logic already exists in `storage.py`, so the core challenge is detecting changes and triggering a re-render.

Textual provides `FileMonitor` but it is internal. The `watchfiles` library (Rust-based, used by uvicorn) provides efficient cross-platform file watching.

## Goals / Non-Goals

**Goals:**
- Detect markdown file changes on disk and reload content automatically
- Preserve comments, cursor position, and scroll position across reloads
- In directory mode, detect newly added `.md` files
- Show a notification on reload

**Non-Goals:**
- Watching non-markdown files (e.g., images, CSS)
- Collaborative/multi-user real-time editing
- Auto-saving review state on external change
- Debouncing rapid successive changes (watchfiles handles this internally)

## Decisions

### 1. File watcher: `watchfiles` library

**Choice**: Use `watchfiles.awatch()` (async) integrated into Textual's event loop via a background worker.

**Alternatives considered**:
- *`watchdog`*: Heavier, thread-based, more complex API. Rejected.
- *Polling with timer*: Inefficient, delayed, battery-unfriendly. Rejected.
- *Textual FileMonitor*: Internal/undocumented API. Rejected.

**Rationale**: `watchfiles` is lightweight, async-native, and handles OS-specific backends (FSEvents on macOS, inotify on Linux).

### 2. Reload strategy

On file change detected:
1. Re-read file content from disk
2. Compute new content hash
3. If hash differs from current: reconcile drift, re-preprocess mermaid, re-render markdown
4. Restore cursor to same block index (clamped to new block count) and scroll position
5. Show Textual notification: "File reloaded: {filename}"

### 3. Watch scope

- **Single file mode**: Watch the specific file(s) passed as arguments
- **Directory mode**: Watch the directory recursively for `.md` files; detect new files and append to the file list

### 4. Worker lifecycle

- Start watcher in `on_mount()`
- Cancel watcher in `on_unmount()`
- Use Textual's `self.run_worker()` for async background task

## Risks / Trade-offs

- **[File deleted while viewing]** → Show notification "File removed: {filename}", keep current content in view
- **[Rapid edits]** → `watchfiles` debounces by default (300ms); acceptable for review use case
- **[New dependency]** → `watchfiles` is well-maintained, small footprint, acceptable trade-off
