9.4 KiB
Owlen TUI UX & Keybinding Playbook
Last updated: October 25, 2025
This playbook documents the design principles, modal ergonomics, command metadata, theming tokens, and animation policy that guide Owlen’s terminal UI. Use it both as a contributor reference and as a migration guide when extending custom keymaps or UI affordances.
1. Modal Philosophy
Owlen embraces a Vim-inspired modal workflow with discoverability helpers layered on top.
| Mode | Entry | Primary Purpose | Escape |
|---|---|---|---|
| Normal | Esc, Ctrl+[, application start |
Navigation, pane switching, command prefixes, leader chords | i, :, ?, F1 |
| Editing | i, a, Enter in Normal |
Compose prompt, multi-line editing, history cycling (Ctrl+↑/↓) |
Esc |
| Visual | v in Normal |
Region selection across chat, thinking, and input panes | Esc, v |
| Command | : |
Run palette commands (:session save, :mode code, :limits) |
Esc, Enter |
| Help | F1, ? |
Cheat sheet tabs, onboarding tour | Esc, F1 |
| Browsers | :sessions, :themes, repo search keys |
Context-specific pickers with shared navigation primitives | Esc |
Modal transitions fire AppEvent::Composer::ModeChanged, enabling keymap
state to reset cleanly (see ChatApp::set_input_mode). Maintain this flow
when adding new modes to avoid orphaned key sequences.
Focus Shortcuts
Ctrl+1…5focus Files, Chat, Code, Thinking, Input (mirrors leader chords).Tab/Shift+Tabcycle panes;g ttoggles Files visibility in Vim keymap.Ctrl+Alt+5(Vim) /Alt+5(Emacs) jump back to the input editor.
Keep focus hops single-chord and mnemonic. Prefer documenting any new shortcut
in the cheat sheet (render_guidance_cheatsheet) and the status HUD hints.
2. Keybinding Design & Migration
Built-in Profiles
- Vim (default): stored in
crates/owlen-tui/keymap.toml. - Emacs: stored in
crates/owlen-tui/keymap_emacs.toml.
Switch at runtime via :keymap vim|emacs; persist with
ui.keymap_profile = "vim" or "emacs" in config.toml.
Custom Keymaps
Set ui.keymap_path = "/absolute/path/to/keymap.toml" to override the built-in
profiles. The schema matches the shipped TOML files:
[[bindings]]
mode = "normal"
sequence = ["g", "t"]
command = "workspace.toggle_files"
Migration notes (v0.2+)
- Multi-step sequences: All keymaps now support arbitrary-length
sequences (
Ctrl+W,w,Ctrl+K,←). Update custom maps to the trie syntax if you previously shadowed hard-coded Rust handlers. - Leader remapping:
ui.keymap_leaderdefaults to space. Custom profiles should mirror the new leader sections so the cheat sheet can surface alternate hints (binding_pair_string). - Discoverability hooks: Register new commands in
commands::catalog()with category, summary, tags, and optionalpreviewcallback. The command palette relies on this metadata for fuzzy search and tag filtering. - Help overlay: If you introduce new focus or layout commands, add them to
build_cheatsheet_sectionsso onboarding and help stay in sync.
Run cargo test -p owlen-tui --test chat_snapshots after keymap changes to
refresh guidance snapshots.
3. Command Metadata Schema
Located in crates/owlen-tui/src/commands/catalog.rs,
each command descriptor should populate:
category: High-level grouping shown in the palette (navigation,session,provider).keywords: Fuzzy aliases; include verbs (open, focus), nouns (chat, files), and tags (#agent).key_hint: Optional string rendered in previews (e.g.,Ctrl+Shift+F).modes: Restrict availability byInputModewhen needed (e.g., editing-only commands).preview: Use for sidecar previews (commands::Preview), returning lines that explain impact.
When adding new commands:
- Define the handler in
commands::handlers. - Register metadata in
catalog()and supply tests incrates/owlen-tui/tests/state_tests.rsor palette-specific snapshots. - Update the cheat sheet if the command introduces a new focus or mode affordance.
4. Theming & Layer Tokens
Themes live in owlen_core::theme. The TUI applies a glass/neon layer via
GlassPalette::for_theme_with_mode using config.ui.layers:
| Setting | Default | Description |
|---|---|---|
shadow_elevation |
2 |
Depth of drop shadow around the chat stage. |
glass_tint |
0.82 |
Opacity mix between base theme background and frosted layer. |
neon_intensity |
60 |
Percentage controlling accent saturation. |
focus_ring |
true |
Draws neon outlines around the active stage container. |
Best practices
- Keep contrasts AA+; avoid low-alpha custom tints when
accessibility_high_contrast = true. - Re-render custom palettes through the snapshot suite to catch regression diffs.
5. Animation Policy
Controlled by config.ui.animations:
| Field | Effect | Range |
|---|---|---|
micro |
Enables pane glow, gauge easing, mode flash. | true/false |
gauge_smoothing |
Exponential smoothing factor for usage gauges. | 0.05–1.0 |
pane_decay |
Decay applied to pulse effects on pane switches. | 0.2–0.95 |
Accessibility flags (ui.accessibility.high_contrast, ui.accessibility.reduced_chrome) automatically disable micro animations. When adding new animations:
- Guard with
ChatApp::micro_animations_enabled(). - Provide non-animated fallbacks (e.g., direct gauge
snap). - Update documentation and consider adding snapshot coverage under both animated and non-animated configurations.
6. Status Surface & Toasts
The status HUD (render_status) now renders three columns:
- Left: Mode/operating badges, focus hints, agent state, help shortcuts.
- Center: Primary status message with auto-leveled badge (info/success/warning/error) and contextual usage gauges.
- Right: Repository/path summary, provider & model badge, streaming hints, and toast history.
Toast enhancements:
- Icons per severity (
ⓘ,✔,⚠,✖). - Optional keyboard hints via
push_toast_with_hint. - Progress bar countdown plus remaining seconds.
- Persistent history (20 entries) exposed to the HUD for quick recall.
Guidelines
- Provide actionable hints (e.g.,
"F12 · Debug log",":limits"). - Reserve
ToastLevel::Errorfor recoverable issues the user must address. - Use status primary line for the most recent action; employ
system_statusfor secondary context.
7. Contributor Checklist
When modifying TUI UX or keybindings:
- Update this playbook if the change affects modal ergonomics, theming tokens, animation policy, or keymap conventions.
- Extend the cheat sheet / onboarding overlays for new focus or command shortcuts.
- Refresh snapshots:
INSTA_UPDATE=always cargo test -p owlen-tui --test chat_snapshots. - Run
cargo clippy -p owlen-tui -- -D warningsand theowlen-tuitest suite. - Document user-facing changes in
CHANGELOG.md.
Keeping these steps in sync ensures Owlen’s keyboard-first UX remains predictable, accessible, and discoverable.
8. Screenshot Pipeline
Use the scripted pipeline to regenerate gallery assets and documentation illustrations:
cargo xtask screenshotsemits ANSI dumps underimages/generatedand, by default, converts them to PNG withchafa. Pass--no-pngto skip PNG rendering or--chafa /path/to/chafato override the binary. Each scene is deterministic—no network calls—and mirrors the regression snapshots.- The pipeline reuses the same stub provider harness as the snapshot tests, so
new scenes should be added in tandem with
chat_snapshots.rsto keep visual regression coverage and documentation imagery aligned.
9. Transcript Compression
- The compactor lives under
[chat]inconfig.toml. Defaults keepauto_compress = true,trigger_tokens = 6000, and retain the last eight turns verbatim. - Strategy is configurable:
providersummaries call back through the active model (orchat.model_override), whilelocaluses a heuristic bullet list for fully offline runs. - Users can disable the feature per session with
owlen --no-auto-compress, or at runtime via:compress auto on|off.:compress nowtriggers an immediate compaction even when auto mode is disabled. - Each compression pass replaces older turns with a system summary annotated by
message.metadata.compression(strategy, timestamps, token deltas, and the archived message ids) to support audits and future rehydration tools.