# Complete llmfit TUI Keyboard Shortcuts Reference: Modal Navigation Guide

> Master llmfit TUI keyboard shortcuts with this comprehensive guide. Learn modal navigation, list scrolling, visual selection, and essential commands for efficient interaction.

- Repository: [Alex Jones/llmfit](https://github.com/AlexsJones/llmfit)
- Tags: api-reference
- Published: 2026-08-19

---

**The llmfit TUI uses a modal interface where `q` or `Esc` quits the current view, `j`/`k` navigate lists, `v` enters visual selection mode, and all input is handled in [`llmfit-tui/src/tui_events.rs`](https://github.com/AlexsJones/llmfit/blob/main/llmfit-tui/src/tui_events.rs) dispatching to mode-specific handlers like `handle_normal_mode` and `handle_visual_mode`.**

The **llmfit TUI keyboard shortcuts** are implemented in a modal terminal interface built with *ratatui* and *crossterm*. Every keystroke is processed in [`llmfit-tui/src/tui_events.rs`](https://github.com/AlexsJones/llmfit/blob/main/llmfit-tui/src/tui_events.rs) where the `handle_events` function routes input to mode-specific handlers that manipulate the central `App` state defined in [`llmfit-tui/src/tui_app.rs`](https://github.com/AlexsJones/llmfit/blob/main/llmfit-tui/src/tui_app.rs). Understanding these vim-inspired bindings is essential for navigating the model browser, running benchmarks, and managing downloads efficiently.

## Understanding llmfit's Modal Architecture

The interface isolates concerns across distinct input modes. **Normal mode** displays the primary model table, while **Visual mode** enables range selection, **Select mode** targets specific columns, and **Search mode** filters the dataset. This design keeps the rendering logic in [`tui_ui.rs`](https://github.com/AlexsJones/llmfit/blob/main/tui_ui.rs) stateless while ensuring shortcuts affect only the intended UI component. Each mode handler—`handle_normal_mode`, `handle_visual_mode`, `handle_select_mode`, and `handle_search_mode`—matches `crossterm::event::KeyCode` values to methods on the `App` struct.

## Normal Mode Shortcuts

Normal mode is the default state when launching llmfit. The `handle_normal_mode` function (lines 49-138 in [`tui_events.rs`](https://github.com/AlexsJones/llmfit/blob/main/tui_events.rs)) processes these bindings.

### Navigation Controls

- **j** or **Down**: Move down in lists (benchmark view, multi-compare view, or tables).
- **k** or **Up**: Move up in lists.
- **Ctrl-u**: Half-page up (`app.half_page_up()`).
- **Ctrl-d**: Half-page down (`app.half_page_down()`).
- **PageUp** / **PageDown**: Full-page navigation (`app.page_up()` / `app.page_down()`).
- **g** or **Home**: Jump to top or bottom of the list (`app.cycle_top_bottom()`).
- **h** / **l** (in multi-compare): Scroll columns left/right (`app.multi_compare_scroll_left()` / `right()`).
- **Left** / **Right** (in multi-compare): Same horizontal scrolling as **h** / **l**.

### Filtering and Sorting

- **/**: Open the search box (`app.enter_search()`).
- **f**: Cycle through fit filters (Perfect → Good → ...).
- **F**: Open the filter popup for range filters, sorting, and fit criteria (`app.open_filter_popup()`).
- **a**: Cycle availability filter (All / Installed / GGUF).
- **T**: Cycle Tensor-Parallel compatibility filter.
- **s**: Cycle sort column (`app.cycle_sort_column()`).
- **i**: Toggle "installed-first" sort when providers are available (`app.toggle_installed_first()`).

### View Management

- **Enter**: Toggle detail view or expand benchmark details (`app.toggle_detail()`).
- **t**: Switch theme between dark and light (`app.cycle_theme()`).
- **p**: Open the plan view (`app.open_plan_mode()`).
- **P**: Open provider selection popup.
- **U**: Open use-case popup.
- **C**: Open capability popup.
- **L**: Open license popup.
- **R**: Open runtime popup.
- **S**: Open simulation popup.
- **h**: Open help popup (`app.open_help_popup()`).
- **b**: Open benchmarks view (community leaderboard) (`app.open_benchmarks()`).
- **D**: Toggle download manager view (`app.toggle_downloads()`).

### Model Actions

- **v**: Enter visual mode for range selection (`app.enter_visual_mode()`).
- **V**: Enter select mode for column-specific actions (`app.enter_select_mode()`).
- **m**: Mark or unmark selected model for comparison (`app.mark_selected_for_compare()`).
- **c**: Toggle compare view (`app.toggle_compare_view()`).
- **x**: Clear all compare marks (`app.clear_compare_mark()`).
- **y**: Copy selected model name to clipboard (`app.copy_selected_model_name()`).
- **d**: Start model download via best provider (`app.start_download()`), requires confirmation if no download is active.
- **r**: Refresh installed models (`app.refresh_installed()`).
- **I**: Open or rerun live inference benchmark (`app.open_bench()` / `app.rerun_bench()`).
- **A**: Open advanced config popup (`app.open_advanced_config_popup()`).
- **q** or **Esc**: Quit or close current view, setting `should_quit = true` if at the top level.

## Visual Mode Shortcuts

Activated by pressing **v** in normal mode, `handle_visual_mode` (lines 41-62) enables selection ranges.

- **Esc**, **q**, or **v**: Exit visual mode.
- **j** / **Down**, **k** / **Up**, **Ctrl-u**, **Ctrl-d**, **PageUp**, **PageDown**, **g** / **Home**: Navigation helpers that extend the visual selection.
- **m**: Mark selected rows for comparison.
- **c**: Compare the first and last rows of the current visual selection.

## Select Mode Shortcuts

Activated by **V** in normal mode, `handle_select_mode` (lines 65-82) targets specific columns.

- **Esc** or **q**: Exit select mode.
- **h** / **Left** or **l** / **Right**: Move column cursor left or right.
- **Enter** or **Space**: Activate filter for the current column.
- **j** / **Down** or **k** / **Up**: Move row cursor up or down.

## Search Mode Shortcuts

When the search box is open via **/**, `handle_search_mode` (lines 85-106) manages text input.

- **Esc** or **Enter**: Close the search box.
- **Backspace** or **Delete**: Remove characters.
- **Ctrl-u**: Clear the entire search query.
- **←** / **→**: Move cursor inside the search string.
- **Any printable character** (without Ctrl/Alt modifiers): Insert character via `app.search_input(c)`.
- **↑** / **↓**: Navigate the list while typing a search term.

## Popup and Sub-Modal Shortcuts

Provider, use-case, capability, license, and runtime popups share common bindings in their respective handlers (e.g., provider at lines 9-44, use-case at lines 86-98).

- **Esc**, **q**, or the popup's capital letter (**U**, **C**, **L**, **R**): Close the popup.
- **↑** / **k**: Move selection up.
- **↓** / **j**: Move selection down (Shift-scrolls by 25 lines).
- **Space** or **Enter**: Toggle the highlighted item.
- **a**: Select all providers (provider popup only).
- **n**: Deselect all providers (provider popup only).
- **Ctrl-u**: Clear typed filter text.
- **Plain ASCII characters**: Filter the list via `provider_search_input`, `use_case_search_input`, etc.

### Filter Popup Controls

In `handle_filter_popup_mode` (lines 68-83):

- **Esc** or **q**: Close filter popup.
- **Enter**: Apply the filter.
- **Tab** / **Down** or **Shift-Tab** / **Up**: Switch between fields.
- **←** / **→**: Move cursor inside numeric fields.
- **Backspace** / **Delete**: Erase characters.
- **Ctrl-u**: Clear the active input (except enum fields).
- **Space**: Toggle sort direction or cycle fit/availability values.
- **Digits** or **.** (period): Input numeric values like RAM thresholds.

### Plan View Controls

The `handle_plan_mode` function (lines 67-84) manages the hardware planning interface.

- **Esc**: Close plan view.
- **Tab** / **Down** / **j** or **Shift-Tab** / **Up** / **k**: Move between plan fields.
- **←** / **→**: Move cursor inside the current field.
- **Backspace** / **Delete**: Remove characters.
- **Ctrl-u**: Clear the current field.
- **Printable characters**: Insert into the field (numbers and periods allowed).

### Simulation and Advanced Config

Both `handle_simulation_mode` (lines 16-31) and `handle_advanced_config_mode` (lines 51-68) use similar editing shortcuts.

- **Esc** or **q**: Close popup.
- **Enter**: Apply changes (or simulated config).
- **Tab** / **Down** / **j** or **Shift-Tab** / **Up** / **k**: Navigate between fields.
- **←** / **→**: Cursor movement within fields.
- **Backspace** / **Delete** or **Ctrl-u**: Edit or clear field contents.
- **Ctrl-r**: Reset to real hardware (simulation) or defaults (advanced config).
- **Digits** or **.** (period): Input numeric values.

### Benchmark Hardware Picker

Within `handle_benchmarks_mode` (lines 145-184), the hardware picker sub-modal responds to:

- **Esc**, **q**, or **H**: Close hardware picker.
- **↑** / **k** or **↓** / **j**: Move selection.
- **Enter** or **Space**: Confirm hardware selection.

## Download Manager Controls

In `handle_download_manager_mode` (lines 83-133), the download interface uses:

- **Esc**, **D**, or **q**: Close download manager.
- **Tab** or **Shift-Tab**: Cycle focus between History and Config panes.
- **↑** / **k** (History focus): Move up in download history.
- **↓** / **j** (History focus): Move down in download history.
- **x** (History focus): Mark selected download for deletion (requires confirmation).
- **e** (Config focus): Edit the download directory.
- **During edit mode**: **Esc**, **Enter**, **←** / **→**, **Backspace**, **Delete**, **Ctrl-u**, and printable chars perform standard line-editing on the path field.

## Help System

The `handle_help_popup_mode` (lines 1-14) provides documentation browsing.

- **Esc**, **h**, or **q**: Close help.
- **↑** / **k** or **↓** / **j**: Scroll help text up or down.

## Programmatic Shortcut Access

You can invoke these shortcuts programmatically for testing or automation by constructing `crossterm::event::KeyEvent` objects and calling the handlers directly.

```rust
// Simulate pressing "/" to open the search box
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
let ev = KeyEvent::new(KeyCode::Char('/'), KeyModifiers::NONE);

// In tests, call the handler directly
crate::tui_events::handle_normal_mode(&mut app, ev);
assert!(app.input_mode == InputMode::Search);

```

```rust
// Toggle the "installed-first" sort while any provider is available
let ev = KeyEvent::new(KeyCode::Char('i'), KeyModifiers::NONE);
crate::tui_events::handle_normal_mode(&mut app, ev);
assert!(app.installed_first);

```

```rust
// Verify that the plan field accepts "q4_k" input without closing
let mut app = crate::tui_events::tests::plan_mode_app();
app.plan_field = PlanField::KvQuant;
for c in ['q','4','_','k'] {
    crate::tui_events::handle_plan_mode(&mut app,
        KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE));
}
assert_eq!(app.input_mode, InputMode::Plan);
assert_eq!(app.plan_kv_quant_input, "q4_k");

```

These examples demonstrate how the `#[cfg(test)]` module at the end of [`tui_events.rs`](https://github.com/AlexsJones/llmfit/blob/main/tui_events.rs) validates that keyboard bindings manipulate the `App` state correctly without requiring a live terminal.

## Summary

- **All keyboard handling** is centralized in [`llmfit-tui/src/tui_events.rs`](https://github.com/AlexsJones/llmfit/blob/main/llmfit-tui/src/tui_events.rs), where `handle_events` dispatches to mode-specific functions like `handle_normal_mode` and `handle_visual_mode`.
- **Navigation** relies on vim-style bindings: **j**/**k** for vertical movement, **h**/**l** for horizontal scrolling, and **Ctrl-u**/**Ctrl-d** for half-page jumps.
- **Modes** include Normal (browsing), Visual (range selection), Select (column targeting), Search (text filtering), and various popups for providers, filters, and configuration.
- **Global exit keys** are **q** and **Esc**, which close the current view or quit the application when at the top level.
- **Comparison workflow**: Use **m** to mark models, **v** to enter visual mode for range selection, and **c** to open the comparison view.
- **Programmatic testing** is supported by calling handlers directly with `KeyEvent` objects constructed via `crossterm`.

## Frequently Asked Questions

### How do I exit any mode or popup in the llmfit TUI?

Press **Esc** or **q** to exit the current mode or close the active popup. In normal mode, these keys set `should_quit = true` to exit the application entirely, while in sub-modes like visual, select, or search, they return you to normal mode without quitting the program. Specific popups like the provider selector (**P**) also close when you press their activation key again.

### What are the vim-style navigation keys in llmfit?

The llmfit TUI uses standard vim motion keys: **j** moves down, **k** moves up, **h** scrolls columns left, and **l** scrolls columns right. These work in normal mode and extend selection in visual mode. Additionally, **g** or **Home** jumps to the top or bottom of lists, while **Ctrl-u** and **Ctrl-d** perform half-page scrolling.

### How do I search and filter models in the interface?

Press **/** to enter search mode and type to filter the model list dynamically. For advanced filtering, press **F** to open the filter popup where you can set range filters for RAM and other metrics, cycle fit quality with **f**, toggle availability with **a**, or filter by Tensor-Parallel compatibility with **T**. Use **s** to cycle through sort columns in the main view.

### How do I compare multiple models side-by-side?

First, navigate to a model and press **m** to mark it for comparison. Enter **visual mode** by pressing **v**, select a range using **j**/**k**, then press **m** again to mark multiple rows, or press **c** to compare the first and last rows of your selection. Press **c** in normal mode to toggle the compare view, and **x** to clear all comparison marks.