Story
As a person using xmd repl, I want to move between parts of the screen with Tab and navigate their controls with arrow keys, so reaching another part of the interface does not require stepping through every control along the way.
For example, while navigating rows in the sidebar, Tab moves to the next top-level focus region regardless of how many sidebar rows exist. Up, Down, Left and Right navigate within the active region. Shift+Tab moves back between regions.
Current gap
Keyboard traversal treats the interface as one long sequence of focusable controls. Moving to another pane can require many Tab presses, and adding controls makes that journey longer.
The implementation already has a mounted component tree. Freedom's focusChain() flattens its focusable descendants, and REPL dispatch sends Tab and Backtab through that sequence. Arrow keys currently have no normalized navigation event. The gap is the navigation model, rather than the absence of an underlying tree.
Accepted direction
- Focus navigation follows a tree of regions and their children. A region is a recognizable part of the interface whose controls are navigated together.
- Tab and Shift+Tab move forward and backward between the roots of those regions. They do not enumerate every descendant before leaving a region.
- Up, Down, Left and Right navigate among children within the active region. Arrow navigation does not become another traversal of the whole screen.
- Increasing the number of children in a region does not increase the number of Tab presses needed to reach another region.
The precise region inventory and navigation details below require Product Owner review before this becomes an implementation handoff.
Decisions before implementation
Prepare a concrete focus-tree diagram and key walkthrough for the empty REPL, populated Entries and Sessions, an open interaction drawer, and the Bindings/Sidekick composition from #883. Settle:
- Which visible parts are region roots, their Tab order, and what focus visibly lands on when entering a region: the root itself, a default child, or its previously focused child.
- How each arrow moves through vertical lists, horizontal controls, nested groups and mixed layouts; what happens at an edge; and whether traversal wraps.
- How text fields and composers use arrows for editing while keeping their neighboring controls reachable.
- How modal drawers constrain the available regions, restore focus when closed, and coexist with the existing History-reachability contract.
- How windowed lists expose further children and how narrow composition or removal of a focused child chooses a surviving focus target.
Update the accepted keyboard contract in specs/repl-spec.md and the affected architecture description with the settled design. In particular, reconcile the current statement that list-window controls have no arrow shortcut. Do not silently reinterpret that statement as already providing this behavior.
Existing boundaries
Freedom remains the sole focus owner within the mounted tree. Region navigation introduces no second focus store or terminal reader. Host input names keys and targets; mounted components and their ancestry determine meaning under the established dispatch contract.
Keyboard focus remains distinct from selected entries, scopes and History positions. Moving focus alone does not execute a control, submit a draft or answer an interaction. Background output does not steal focus. Hidden or unmounted surfaces have no navigation targets, and pointer and keyboard interaction agree on the focused control.
Product verification proposal
- Start within a populated sidebar, reach another region with Tab, navigate its children with arrows, and return with Shift+Tab. Repeat with substantially more sidebar rows: the cross-region Tab distance stays the same.
- Traverse a region's children in both directions without unexpectedly moving into another region. Demonstrate the approved behavior for nesting, edges and list windows.
- Move between the main entry input and the Sidekick composer when available. Typing reaches the visibly focused destination; arrow editing follows the approved field contract.
- Open and close a drawer, resize to a narrow terminal and back, and remove the focused child. Focus stays within the permitted visible tree or moves to the approved surviving target.
- Show that focus movement preserves selection, drafts and pending interactions and performs no activation. Background Agent activity preserves the current focus.
Exercise actual terminal key input through REPL dispatch and capture the visible focus destination. A helper-only test or a flattened chain with a few skipped controls does not establish the region model. The Architect and Product Owner refine this proposal before the Planner freezes acceptance.
Relationships and scope
Follow-on REPL Story related to Quest #827. #881 owns original visual parity and already requires visible focus distinct from selection; this Story owns the changed keyboard-navigation model. Coordinate with #883 for right-pane tabs and its independent composer. Preserve those active contracts rather than rewriting their scope through this Story.
Relevant implementation boundaries are packages/cli/src/repl/input.ts, reconcile.ts, and the vendored Freedom lib/focus.ts. Existing composition and terminal regression entrypoints are packages/cli/tests/repl-composition.test.ts and packages/cli/tests/repl-terminal.test.ts.
Exclude a renderer replacement, a general public UI framework, new panes, session-management features and changes to execution or Journal semantics.
Story
As a person using
xmd repl, I want to move between parts of the screen with Tab and navigate their controls with arrow keys, so reaching another part of the interface does not require stepping through every control along the way.For example, while navigating rows in the sidebar, Tab moves to the next top-level focus region regardless of how many sidebar rows exist. Up, Down, Left and Right navigate within the active region. Shift+Tab moves back between regions.
Current gap
Keyboard traversal treats the interface as one long sequence of focusable controls. Moving to another pane can require many Tab presses, and adding controls makes that journey longer.
The implementation already has a mounted component tree. Freedom's
focusChain()flattens its focusable descendants, and REPL dispatch sends Tab and Backtab through that sequence. Arrow keys currently have no normalized navigation event. The gap is the navigation model, rather than the absence of an underlying tree.Accepted direction
The precise region inventory and navigation details below require Product Owner review before this becomes an implementation handoff.
Decisions before implementation
Prepare a concrete focus-tree diagram and key walkthrough for the empty REPL, populated Entries and Sessions, an open interaction drawer, and the Bindings/Sidekick composition from #883. Settle:
Update the accepted keyboard contract in
specs/repl-spec.mdand the affected architecture description with the settled design. In particular, reconcile the current statement that list-window controls have no arrow shortcut. Do not silently reinterpret that statement as already providing this behavior.Existing boundaries
Freedom remains the sole focus owner within the mounted tree. Region navigation introduces no second focus store or terminal reader. Host input names keys and targets; mounted components and their ancestry determine meaning under the established dispatch contract.
Keyboard focus remains distinct from selected entries, scopes and History positions. Moving focus alone does not execute a control, submit a draft or answer an interaction. Background output does not steal focus. Hidden or unmounted surfaces have no navigation targets, and pointer and keyboard interaction agree on the focused control.
Product verification proposal
Exercise actual terminal key input through REPL dispatch and capture the visible focus destination. A helper-only test or a flattened chain with a few skipped controls does not establish the region model. The Architect and Product Owner refine this proposal before the Planner freezes acceptance.
Relationships and scope
Follow-on REPL Story related to Quest #827. #881 owns original visual parity and already requires visible focus distinct from selection; this Story owns the changed keyboard-navigation model. Coordinate with #883 for right-pane tabs and its independent composer. Preserve those active contracts rather than rewriting their scope through this Story.
Relevant implementation boundaries are
packages/cli/src/repl/input.ts,reconcile.ts, and the vendored Freedomlib/focus.ts. Existing composition and terminal regression entrypoints arepackages/cli/tests/repl-composition.test.tsandpackages/cli/tests/repl-terminal.test.ts.Exclude a renderer replacement, a general public UI framework, new panes, session-management features and changes to execution or Journal semantics.