[BUG] Keybinds execute in background when dialogs/pickers are open #3777

Closed
opened 2026-02-16 17:41:26 -05:00 by yindo · 2 comments
Owner

Originally created by @anntnzrb on GitHub (Dec 23, 2025).

Originally assigned to: @kommander on GitHub.

Description

Global keybinds (like Tab for agent cycling) continue to execute when a dialog or picker is open in the TUI. This causes unintended side effects in the background while the user is interacting with a modal.

Example: When the Model Selector (<leader>m) or Command Palette (Ctrl+P) is open, pressing Tab will cycle through agents in the background instead of being ignored or handled by the dialog.

Note: This bug likely also exists in the Desktop/Web app (packages/app/), where packages/app/src/context/command.tsx has a similar pattern - the keybind handler does not check if a dialog is active before executing commands.

Root Cause

In packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx, there are two useKeyboard handlers:

  1. Handler in init() (lines 46-55): Processes all registered commands with keybinds (including agent.cycle). This handler checks suspended() but does not check if a dialog is open (dialog.stack.length > 0).

  2. Handler in CommandProvider (lines 100-108): Only handles opening the command palette. This handler correctly checks both suspended() and dialog.stack.length > 0.

The inconsistency between these two handlers causes the bug.

Technical Analysis

Options Considered:

  1. Add dialog.stack.length > 0 check (chosen solution)

    • Add the same guard used in CommandProvider to the init() handler
    • Minimal change (1 line), follows existing pattern in the same file
    • No architectural changes needed
  2. Use command.keybinds(false/true) in dialogs (similar to autocomplete)

    • Make dialogs suspend keybinds when opening and resume when closing
    • Would require DialogProvider to access CommandProvider, but DialogProvider is initialized before CommandProvider in the component tree, making this impractical without restructuring
  3. Reactive effect on dialog.stack.length

    • Use createEffect to observe dialog state and update suspendCount
    • More complex than option 1, achieves the same result indirectly

Decision: Option 1 was chosen because:

  • It follows the existing pattern already used in the same file (line 102)
  • It's consistent with how session/index.tsx handles the same scenario (line 254)
  • Minimal change with no risk of introducing regressions
  • No architectural changes required

Steps to reproduce

  1. Open the TUI (opencode)
  2. Open any dialog/picker (e.g., Ctrl+P for Command Palette or <leader>m for Model Selector)
  3. While the dialog is open, press Tab (agent cycle keybind)
  4. Close the dialog
  5. Observe that the agent has changed in the background

Expected: Keybinds should not execute while a dialog is open
Actual: Keybinds execute in the background, causing unintended state changes

OpenCode version

v1.0.191

Operating System

macOS (applies to all platforms)

Terminal

Any terminal

Originally created by @anntnzrb on GitHub (Dec 23, 2025). Originally assigned to: @kommander on GitHub. ### Description Global keybinds (like `Tab` for agent cycling) continue to execute when a dialog or picker is open in the TUI. This causes unintended side effects in the background while the user is interacting with a modal. **Example:** When the Model Selector (`<leader>m`) or Command Palette (`Ctrl+P`) is open, pressing `Tab` will cycle through agents in the background instead of being ignored or handled by the dialog. > **Note:** This bug likely also exists in the Desktop/Web app (`packages/app/`), where `packages/app/src/context/command.tsx` has a similar pattern - the keybind handler does not check if a dialog is active before executing commands. ### Root Cause In `packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx`, there are two `useKeyboard` handlers: 1. **Handler in `init()` (lines 46-55):** Processes all registered commands with keybinds (including `agent.cycle`). This handler checks `suspended()` but does **not** check if a dialog is open (`dialog.stack.length > 0`). 2. **Handler in `CommandProvider` (lines 100-108):** Only handles opening the command palette. This handler correctly checks both `suspended()` and `dialog.stack.length > 0`. The inconsistency between these two handlers causes the bug. ### Technical Analysis **Options Considered:** 1. **Add `dialog.stack.length > 0` check** (chosen solution) - Add the same guard used in `CommandProvider` to the `init()` handler - Minimal change (1 line), follows existing pattern in the same file - No architectural changes needed 2. **Use `command.keybinds(false/true)` in dialogs** (similar to autocomplete) - Make dialogs suspend keybinds when opening and resume when closing - Would require `DialogProvider` to access `CommandProvider`, but `DialogProvider` is initialized before `CommandProvider` in the component tree, making this impractical without restructuring 3. **Reactive effect on `dialog.stack.length`** - Use `createEffect` to observe dialog state and update `suspendCount` - More complex than option 1, achieves the same result indirectly **Decision:** Option 1 was chosen because: - It follows the existing pattern already used in the same file (line 102) - It's consistent with how `session/index.tsx` handles the same scenario (line 254) - Minimal change with no risk of introducing regressions - No architectural changes required ### Steps to reproduce 1. Open the TUI (`opencode`) 2. Open any dialog/picker (e.g., `Ctrl+P` for Command Palette or `<leader>m` for Model Selector) 3. While the dialog is open, press `Tab` (agent cycle keybind) 4. Close the dialog 5. Observe that the agent has changed in the background **Expected:** Keybinds should not execute while a dialog is open **Actual:** Keybinds execute in the background, causing unintended state changes ### OpenCode version v1.0.191 ### Operating System macOS (applies to all platforms) ### Terminal Any terminal
yindo added the opentui label 2026-02-16 17:41:26 -05:00
yindo closed this issue 2026-02-16 17:41:26 -05:00
Author
Owner

@anntnzrb commented on GitHub (Dec 23, 2025):

Fix submitted in #6017

@anntnzrb commented on GitHub (Dec 23, 2025): Fix submitted in #6017
Author
Owner

@github-actions[bot] commented on GitHub (Dec 23, 2025):

For keybind-related issues, please also check our pinned keybinds documentation: #4997

@github-actions[bot] commented on GitHub (Dec 23, 2025): For keybind-related issues, please also check our pinned keybinds documentation: #4997
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#3777