# TUI MVU Migration Guide This guide explains how we are migrating the Owlen terminal UI to a predictable **Model–View–Update (MVU)** architecture. Use it to understand the current layout, decide where new logic belongs, and track which features have already moved to the MVU core. --- ## Goals - Make UI state transitions pure and testable. - Reduce duplicated control flow inside `chat_app.rs`. - Keep rendering functions dumb; they should depend on read-only view models. - Ensure new features land in MVU-first form so the imperative paths shrink over time. Adopt the checklist below whenever you touch a feature that still lives in the imperative code path. --- ## Module Map (owlen-tui) | Area | Path | Responsibility | MVU Status | | --- | --- | --- | --- | | Core state | `src/app/mvu.rs` | Shared `AppModel`, `AppEvent`, `AppEffect` definitions | **Ready** – composer + consent events implemented | | Legacy app | `src/chat_app.rs` | Orchestrates IO, manages pending tasks, renders via ratatui | **Transitioning** – increasingly delegates to MVU | | Event loop | `src/app/handler.rs` | Converts session messages into app updates | Needs cleanup once message flow is MVU aware | | Rendering | `src/ui.rs` + `src/widgets/*` | Pure rendering helpers that pull data from `ChatApp` | Already read-only; keep that invariant | | Commands | `src/commands/*` | Keymap and palette command registry | Candidate for MVU once palette state migrates | | Shared state | `src/state/*` | Small state helpers (command palette, file tree, etc.) | Each module can become an MVU sub-model | Use the table to find the right starting point before adding new events. --- ## Event Taxonomy Current events live in `app/mvu.rs`. - `AppEvent::Composer` – covers draft changes, mode switches, submissions. - `AppEvent::ToolPermission` – bridges consent dialog choices back to the controller. `AppEffect` represents side effects the imperative shell must execute: - `SetStatus` – surface validation failures. - `RequestSubmit` – hand control back to the async send pipeline. - `ResolveToolConsent` – notify the session controller of user decisions. ### Adding a new feature 1. Extend `AppModel` with the new view state. 2. Create a dedicated event enum (e.g. `PaletteEvent`) and nest it under `AppEvent`. 3. Add pure update logic that mutates the model and returns zero or more effects. 4. Handle emitted effects inside `ChatApp::handle_app_effects`. Keep the event names UI-centric. Provider-side actions should remain in `owlen-core`. --- ## Feature Migration Checklist | Feature | Scope | MVU tasks | Status | | --- | --- | --- | --- | | Composer (input buffer) | Draft text, submission workflow | ✅ `ComposerModel`, `ComposerEvent`, `SubmissionOutcome` | ✅ Complete | | Tool consent dialog | Approval / denial flow | ✅ `AppEvent::ToolPermission`, `AppEffect::ResolveToolConsent` | ✅ Complete | | Chat timeline | Message ordering, cursor, scrollback | Model struct for timeline + events for history updates | ☐ TODO | | Thinking pane | Agent reasoning text, auto-scroll | Model + event to toggle visibility and append lines | ☐ TODO | | Model picker | Filters, search, selection | Convert `ModelSelectorItem` list + search metadata into MVU | ☐ TODO | | Command palette | Suggestions, history, apply actions | Move palette state into `AppModel` and surface events | ☐ TODO | | File workspace | Pane layout, file tree focus | Represent pane tree in MVU, drive focus + resize events | ☐ TODO | | Toasts & status bar | Transient notifications | Consider MVU-managed queue with explicit events | ☐ TODO | When you pick up one of the TODO rows, document the plan in the PR description and link back to this table. --- ## Migration Playbook 1. **Inventory state** – list every field in `ChatApp` that your feature touches. 2. **Define view model** – move the persistent state into `AppModel` (or a new sub-struct). 3. **Write events** – describe all user intents and background updates as `AppEvent` variants. 4. **Translate side effects** – whenever the update logic needs to call into async code, emit an `AppEffect`. Handle it inside `handle_app_effects`. 5. **Refactor call sites** – replace direct mutations with `apply_app_event` calls. 6. **Write tests** – cover the pure update function with table-driven unit tests. 7. **Remove duplicates** – once the MVU path handles everything, delete the legacy branch in `chat_app.rs`. This flow keeps commits reviewable and avoids breaking the live UI during migration. --- ## Testing Guidance - **Unit tests** – cover the pure update functions inside `app/mvu.rs`. - **Integration tests** – add scenarios to `crates/owlen-tui/tests/agent_flow_ui.rs` when side effects change. - **Golden behaviour** – ensure the ratatui renderers still consume read-only data; add lightweight snapshot tests if needed. - **Manual verification** – run `cargo run -p owlen-cli -- --help` to open the TUI and confirm the migrated feature behaves as expected. Every new MVU feature should land with unit tests plus a note about manual validation. --- ## Tracking TODOs - Keep this file up to date when you migrate a feature. - Add inline `// TODO(mvu)` tags in code with a short description so they are easy to grep. - Use the `docs/` folder for design notes; avoid long comment blocks inside the code. Future contributors should be able to glance at this document, see what is done, and understand where to continue the migration. --- Questions? Reach out in the Owlen discussion board or drop a note in the relevant PR thread. Consistent updates here will keep MVU adoption predictable for everyone.