5.6 KiB
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
- Extend
AppModelwith the new view state. - Create a dedicated event enum (e.g.
PaletteEvent) and nest it underAppEvent. - Add pure update logic that mutates the model and returns zero or more effects.
- 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
- Inventory state – list every field in
ChatAppthat your feature touches. - Define view model – move the persistent state into
AppModel(or a new sub-struct). - Write events – describe all user intents and background updates as
AppEventvariants. - Translate side effects – whenever the update logic needs to call into async code, emit an
AppEffect. Handle it insidehandle_app_effects. - Refactor call sites – replace direct mutations with
apply_app_eventcalls. - Write tests – cover the pure update function with table-driven unit tests.
- 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.rswhen 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 -- --helpto 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.