Replies: 7 comments
|
Theres a couple PRs for keyboard shortcuts - specifically for settling/archiving threads. Both are from unvouched people but would be really nice to have. I'm happy to help/test however I can to get one of them in. I'd fork and use it for myself but I use t3 connect a lot and I don't think it would work in my own form with the settle shortcut 🙃 |
|
Items 4 and 5 are now covered by #5961 — one PR, since they are two halves of the same focus/visibility decoupling. Both ship as a Item 1 is covered by #5959 (and independently by the earlier #5669 and #4308). I've updated the tracking list at the top accordingly. |
|
Opened #5959 for item 1, the "smallest useful scope" cut described above: Two things learned while building it, relevant to whichever PR lands:
Verified against a live turn — screenshots and a demo video are in the PR. #5669 and #4308 are alternative takes on the same item; no preference from my side on whose diff lands as long as the gap closes. |
|
Could Right now the only way to start annotating the preview is clicking the button in the toolbar. There's no command id for it, so there's nothing to bind. What makes it feel like an oversight: once the annotation overlay is open, the tools already have keys (V, R, D, E). So you can switch tools from the keyboard, but you still have to reach for the mouse to get in there in the first place. Every other thing in the preview — toggle, refresh, focus the URL bar, zoom — already has a command. I've been running it locally as Happy to open a PR if you want it. |
|
What we do to get these shortcuts/PRs added in? even if we can just get the shortcuts in and have no default shortcut and its upto the user to setup a shortcut would be great |
|
Two more in the same spirit — both are per-thread settings that are mouse-only today (no command ID), and both get toggled many times an hour in a plan-then-execute loop:
Both fit the existing (If |
|
FYI Defaults to: |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Tracking
chat.interrupt— interrupt the running turn — addressed by open PRs feat(web): stop the running turn from the keyboard via chat.interrupt #5959, feat(web): add a rebindable thread.interrupt keybinding #5669 and Add stop thread keybinding command #4308thread.renamethread.settle— addressed by open PRs feat(web): add thread.settle keyboard shortcut (mod+shift+s) #4876 and Add shortcut to settle the open thread #4277terminal.focus— addressed by open PR feat(web): add terminal.focus and chat.focusComposer keybindings #5961 (together with 5)chat.focusComposer— addressed by open PR feat(web): add terminal.focus and chat.focusComposer keybindings #5961 (together with 4)env.togglePickerBefore submitting
Area
packages/contracts or packages/shared
Problem or use case
The keybindings system itself is in good shape — file-backed config, hot reload,
whenexpressions, a settings UI. The limitation is thatKeybindingCommandis a closed set (packages/contracts/src/keybindings.ts:50-71), and several everyday actions aren't in it. Each one is already implemented and dispatchable; it just has no command ID, so it stays mouse-only with no way to rebind it.Six that I hit daily:
1. Interrupt a running turn — no keyboard path at all
interruptThreadTurn(packages/client-runtime/src/operations/commands.ts:245) is reachable only through the stop button'sonInterrupt(ChatComposer.tsx:2737).I grepped every
Escapehandler inapps/web/src— 13 of them, and all are dialogs, pickers, inline rename, or selection-clear. None interrupt a run. So stopping an agent requires the mouse, and there's no workaround.This is the one that hurts most, and it's arguably a gap rather than a feature request. Escape-to-interrupt is close to universal in agent UIs, and reaching for the mouse to stop a run that's heading the wrong way is exactly the moment you don't want to.
2. Rename thread
{ id: "rename", label: "Rename thread" }(SidebarV2.tsx:2018). The inline editor already handles Enter and Escape (SidebarV2.tsx:579-594) — only the entry point is missing, and it's the right-click menu.3. Settle / un-settle thread
SidebarV2.tsx:1996-2001, gated on thethreadSettlementcapability (state/entities.ts:200). Context menu only.4. Focus terminal
There's no
terminal.focus. Focus is coupled to visibility: opening the drawer bumpsterminalFocusRequestId(ChatView.tsx:4218). If the drawer is already open and focus sits in the composer, there's no keyboard route into the terminal.5. Focus composer
The mirror image. Composer focus fires on drawer close (
ChatView.tsx:4222-4227) and on thread switch. Type-to-focus (ChatView.tsx:428) bails whenever focus is inside aninputortextarea(ChatView.tsx:383-389) — xterm renders a textarea, so typing in the terminal never brings you back.6. Environment / checkout picker
The "Current checkout" control (
resolveEnvModeLabel,BranchToolbar.logic.ts:58) is a mouse-only menu (BranchToolbar.tsx:184-203). NeitherBranchToolbar.tsxnorBranchToolbarBranchSelector.tsxhas any keyboard handling. Choosing between current checkout and a new worktree is a decision made on nearly every new thread, and today it needs a pointer.Proposed solution
Extend
STATIC_KEYBINDING_COMMANDSand wire the dispatch, following existing naming:chat.interruptthread.renamethread.settleterminal.focuschat.focusComposerenv.togglePickerFor
chat.interrupta default ofescapewith something likewhen: "!terminalFocus"seems right, sincemod+Kis already hardcoded as terminal-clear andcommandPalette.toggleworks around it the same way. Happy to ship it with no default binding if Escape feels too overloaded.Why this matters
The keybinding system is already good enough that the closed command set is what's holding it back — the gap isn't infrastructure, it's coverage. Every action above is one an agent-driven workflow touches many times an hour, and each one currently breaks flow by forcing a reach for the mouse.
chat.interruptin particular is a correctness-of-experience issue rather than a nicety: there is currently no way to stop a running agent from the keyboard.Smallest useful scope
Just
chat.interrupt. It's the only one with no workaround at all, and it's a small change — the command already exists, it needs a command ID and a dispatch branch.Items 2, 3 and 6 are similarly mechanical: existing menu handlers, new command IDs.
Items 4 and 5 are the only ones with real design in them, since focus is currently coupled to panel visibility and would need decoupling. Fine to split those into a follow-up.
Alternatives considered
For focus terminal / focus composer there's a partial workaround:
mod+Jtwice.terminal.togglecallstoggleTerminalVisibility()(ChatView.tsx:4267), which is visibility-only rather than lifecycle, so the terminal session survives the round trip. It works, but toggling a panel to move focus isn't a great story.The other four have no workaround.
I also looked at whether any of this is reachable through the command palette instead — the thread actions are not; they live only in the sidebar context menu.
Risks or tradeoffs
chat.interruptto bareescapeby default needs awhenclause at minimum, and it may be safer to ship the command with no default and let users opt in.thread.rename/thread.settleneed a target. The context-menu versions act on the right-clicked thread; a keybinding would need to act on the active thread, which is a small semantic difference worth being deliberate about.ChatView.tsxthat several other behaviors depend on. This is the main reason to treat it as a separate change.thread.settleis capability-gated, so the command needs to no-op cleanly against pre-settlement servers.Examples or references
Code references are against
23ea08donmain; the behavior was observed on the nightly build0.0.29-nightly.20260727.915.Adjacent open issues, none of which overlap with the actions above:
Contribution
All reactions