feat(web): new threads follow the sidebar project filter - #162
Merged
Conversation
incognitojam
added a commit
that referenced
this pull request
Aug 16, 2026
yngatech-nightly
Bot
force-pushed
the
main
branch
from
August 16, 2026 01:58
5043b5d to
eedd052
Compare
Picking a project in the sidebar filter narrowed the list but had no say in where the next thread went, so the new thread button still asked which project you wanted and creation fell back to the active thread's project. The filter now outranks the viewed thread when resolving a new thread's project, and the button creates in place instead of opening the picker. Within the filtered group the contextual member still wins, so a group spanning environments does not snap back to its representative. chat.new keeps opening the chooser — chat.newLocal is already the "create in the current project" command — and the tooltip follows whichever of the two the button matches. Also corrects the command palette's new-thread shortcut labels, which have advertised the picker's shortcut on the direct-create item since pingdotgg#4026 made chat.new open a picker.
Making chat.newLocal honor the sidebar filter left no way to start a thread beside your current work while the sidebar was narrowed elsewhere, which is the whole point of the command. The filter's precedence now depends on which affordance is asking. The sidebar button belongs to the filtered list, so the filter beats the thread you are viewing and the new draft always shows up in the list you are looking at. chat.newLocal and its palette twin are the other way round: the thread you are viewing wins, and the filter only beats the fallback default so that with nothing open they still land in the project on screen. The two can now resolve differently, so the button's tooltip names chat.newLocal only while both land in the same project.
… healing early Two findings from an independent review of this branch. Shift+click is the mouse twin of chat.newLocal, but a project filter captured it along with the plain click, so the button had two ways to reach the filtered project and none to reach the thread on screen. It now resolves contextually, and the tooltip's shift+click line reappears whenever the modifier changes where the thread lands rather than only while the picker is in play. The filter's self-healing reset cleared any scope whose group it could not find, and an empty group list means projects have not arrived yet rather than that the filter is stale. Every remount or reconnect could silently drop the filter, which is exactly what moving it into a store was meant to prevent, and would have become "resets on every reload" once the filter is persisted.
Shift+click resolving differently from a plain click meant the button's rule could not be stated without narrating an invisible mode, and the divergence only ever showed up while the filter pointed away from the thread on screen. The button now always follows the filter; chat.newLocal remains the way to start a thread beside the one you are viewing. That removes the tooltip branch describing the split and newThreadOriginsAgree with it. While filtered, the button names no shortcut, because chat.new still opens the chooser and chat.newLocal follows the thread on screen.
incognitojam
force-pushed
the
t3code/new-thread-follows-project-filter
branch
from
August 16, 2026 09:22
b82e2cf to
c63b9bd
Compare
incognitojam
enabled auto-merge (squash)
August 16, 2026 09:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Selecting a project in the sidebar filter now decides where the sidebar's New thread button puts the next thread, instead of asking. ⇧⌘N still starts a thread beside the one you have open, and ⌘N still opens the chooser, so a filter never boxes you in. Also fixes command palette shortcut labels that have pointed at the wrong command since pingdotgg#4026.
Before / after
Sidebar New thread, filtered to
orbital-freight. The button used to open the project chooser and advertise ⇧⌘O plus a shift+click hint; it now simply creates in the filtered project.Command palette, same state. The direct-create row advertised the picker's shortcut and the picker advertised none.
Screenshots use a synthetic three-project fixture.
The problem
The sidebar's project filter narrowed the thread list but had no say in where new threads went. With a project selected, New thread still opened the project chooser, and creation resolved through active thread → active draft → first project, ignoring the filter entirely. Mobile has done the right thing here for a while (
resolveDraftProjectSelectionreturnspreserveon an explicit filter); web hadn't caught up.Which project a new thread lands in
The filter's precedence depends on which affordance is asking.
resolveThreadActionProjectReftakes an explicit origin for this, defaulting to"contextual"so a caller that doesn't think about it gets the conservative behavior.chat.newLocal, palette New thread in Xchat.newSo with a thread open in A and the filter on B, the button gives you B and ⇧⌘N gives you A. Both doors stay open without clearing the filter first.
Within a filtered group the member you're already in still wins, so a group spanning environments — the same project local and remote — doesn't snap back to its representative.
The filter moved from
useStateinAppSidebarLayoutinto a small store. It had to: the new-thread shortcuts live in the_chatroute and the command palette mounts at the root, both outside the sidebar tree. That also retires the lifted-above-the-mobile-sheet workaround, and leaves persistence as a self-contained follow-up — the reset guard below is the part that had to land first, since persisting a filter that clears itself on every load would be worse than not persisting it.Shortcut labels
No keybindings changed —
packages/shared/src/keybindings.tsis untouched. What changed is which shortcut each affordance advertises. Defaults:chat.new→ ⌘N and ⇧⌘O;chat.newLocal→ ⇧⌘N.While filtered, the button names no shortcut:
chat.newstill opens the chooser andchat.newLocalfollows the thread on screen, so neither is an honest twin.Pre-existing bug (the ❌ rows)
action:new-threadhas carriedshortcutCommand: "chat.new"since the palette landed in pingdotgg#1103, whenchat.newdid create directly. pingdotgg#4026 (Sidebar v2 beta) madechat.newopen the picker with the new sidebar and 2+ projects, and the label was never updated — so the direct-create item has advertised the picker's shortcut ever since, while the picker itself advertised nothing. Not a regression from this branch; it just lives in the code this branch touches.Not changed
chat.newhas two default bindings,mod+nandmod+shift+o. Label resolution walks the list backwards so later bindings shadow earlier ones — which is what lets a user override beat a default — so ⌘N works but is never shown anywhere in the UI. Surfacing it means reordering those two lines, a real keybinding change, so it's left alone here.Surfaces
chat.new/chat.newLocal, and the palette, wherecontextualProjectReffeeds both the picker's ordering and the "New thread in X" label.!legacySidebarEnabled && projectGroups.length > 1check, so legacy users (wherechat.newstill creates directly at any project count) keep the old labels.docs/user/thread-sidebar.mdgains a "Filtering by project" section — the filter wasn't documented at all.docs/user/keybindings.mdclaimed a new thread inherits "the project you were in", which the filter now outranks when nothing is open.Review
An independent review pass (
oracle) approved the split precedence — it argued a uniform "filter always wins" breakschat.newLocaland a uniform "context always wins" creates drafts with no visible row — and found two bugs, both fixed here:chat.newLocalis the escape.shouldClearProjectScopenow waits while the group list is empty. This one predates the branch.Verification
vp test runonchatThreadActions.test.ts,Sidebar.logic.test.ts, andCommandPalette.logic.test.ts— 135 pass, including new cases for filter precedence per origin, the filter beating only the default for contextual commands, staying on the contextual group member, and the reset guard waiting on unloaded projects. Web typecheck and targeted lint clean.Written by an agent (Claude Code, claude-opus-5).