You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I run a plugin that computes a status for every thread: it needs me, it errored, it is working, it is waiting, it is set aside, or it is done. I want the built-in Thread list to sort by that status, so that inside each project and section the threads that need me come first. I do not want to replace the whole list to get this.
What happens today
The built-in list sorts only by updated time, created time, or title. The only way for a plugin to change the order is experimental_threadList, an exclusive replacement slot. A plugin that takes it has to rebuild rows, grouping, pinning, drag and drop, shortcuts, and windowing, and it falls behind bb as those change.
#2135 asked for the general version: regions, regrouping, and a custom order. It was closed as no longer planned, with "reopen if a concrete host-owned composition need returns". This is one such need, limited to order. experimental_threadList stays the surface for fully custom lists.
What you would expect
A narrow, experimental surface where a plugin supplies only sort keys:
app.experimental_sidebarThreadSorts.register({ id, title, description? }) returns a controller. setKeys({ [threadId]: { rank, at } | null }) replaces every key of that sort: rank ascending, then at descending.
experimental_useSidebarThreadSorts() lets any list read the registered sorts: <pluginId>:<id>, title, and keys. A plugin's sorts and keys go away when it is disabled or its frontend fails to load. After a reload it starts with no keys.
The Thread list shows plugin sorts under Sort by, after the built-ins. It stores the choice in a synced pluginSort preference, also settable with bb thread-list prefs set pluginSort <pluginId>:<id>.
Within every existing group, nested children included, threads are ordered by the plugin's keys, then by the saved built-in sort. Threads without a key follow keyed ones. A worktree group moves as one block, placed by its best-keyed thread.
Grouping, section and project order, collapsed state, and Pinned stay as they are. Without the providing plugin, the list silently uses the built-in sort.
During a drag, a pointer press, keyboard focus in the sidebar, or a rename, the list keeps the plugin keys it had and applies newer keys when that ends. Unkeyed threads and exact ties still follow the live built-in sort.
When new keys reorder rows, the rows the reader sees stay in place.
Docs: the entry in api_to_audit.md, including open questions to settle before stabilizing. The plugin API docs and the authoring skill are updated too.
Context and alternatives
The thread-list test suite passes on the prototype's code (472 tests), and typecheck, lint, and oxfmt are clean for the package.
I also ran a dev build with my own status plugin, which is private. In it I checked:
switching sorts;
Pinned order;
collapsed sections and collapsed children;
children staying nested under their parents;
moving threads between sections;
live reorders on a new question, a thread I stopped, and a status change of the selected thread;
the phone sidebar;
fallback when the plugin is disabled.
That run found one bug, now fixed in the prototype. When a thread moved to the top of its group, React moved nearly every row node, the browser lost its scroll anchor, and the visible rows jumped by one row height. The list now snapshots the visible rows before the update and restores their positions after it.
Alternatives I ruled out:
A full experimental_threadList replacement: too much duplicated behavior.
A built-in "By status" sort over bb's own row indicator: it covers error, waiting, and working, but not states a plugin defines, such as set aside or done. Each workflow also ranks states differently.
This came out of a local bb thread that is not publicly reachable. The commit messages on the branch record the design and the checks.
Before a PR, I would like your call on three points. The full list is in the api_to_audit.md entry linked above.
Is { rank, at } enough, or would you prefer string keys or a comparator?
Should holding the order during interactions and keeping visible rows in place move to the host, so every list behaves the same? Or should they stay in the Thread list?
When the providing plugin is missing, should the list keep the saved choice and fall back silently, as the prototype does? Or should Sort by show the sort as unavailable?
I will open a PR once the shape is agreed.
Checks
I searched open and closed issues for the same request.
If an agent wrote this, the body ends with > AGENT GENERATED.
The workflow
I run a plugin that computes a status for every thread: it needs me, it errored, it is working, it is waiting, it is set aside, or it is done. I want the built-in Thread list to sort by that status, so that inside each project and section the threads that need me come first. I do not want to replace the whole list to get this.
What happens today
The built-in list sorts only by updated time, created time, or title. The only way for a plugin to change the order is
experimental_threadList, an exclusive replacement slot. A plugin that takes it has to rebuild rows, grouping, pinning, drag and drop, shortcuts, and windowing, and it falls behind bb as those change.#2135 asked for the general version: regions, regrouping, and a custom order. It was closed as no longer planned, with "reopen if a concrete host-owned composition need returns". This is one such need, limited to order.
experimental_threadListstays the surface for fully custom lists.What you would expect
A narrow, experimental surface where a plugin supplies only sort keys:
app.experimental_sidebarThreadSorts.register({ id, title, description? })returns a controller.setKeys({ [threadId]: { rank, at } | null })replaces every key of that sort: rank ascending, thenatdescending.experimental_useSidebarThreadSorts()lets any list read the registered sorts:<pluginId>:<id>, title, and keys. A plugin's sorts and keys go away when it is disabled or its frontend fails to load. After a reload it starts with no keys.pluginSortpreference, also settable withbb thread-list prefs set pluginSort <pluginId>:<id>.A prototype is on my fork, based on 4354b88: main...merllinsbeard:bb:feat/plugin-thread-sort (4 commits, head merllinsbeard/bb@7a20062). Main pieces:
Context and alternatives
The thread-list test suite passes on the prototype's code (472 tests), and typecheck, lint, and oxfmt are clean for the package.
I also ran a dev build with my own status plugin, which is private. In it I checked:
That run found one bug, now fixed in the prototype. When a thread moved to the top of its group, React moved nearly every row node, the browser lost its scroll anchor, and the visible rows jumped by one row height. The list now snapshots the visible rows before the update and restores their positions after it.
Alternatives I ruled out:
experimental_threadListreplacement: too much duplicated behavior.This came out of a local bb thread that is not publicly reachable. The commit messages on the branch record the design and the checks.
Before a PR, I would like your call on three points. The full list is in the api_to_audit.md entry linked above.
{ rank, at }enough, or would you prefer string keys or a comparator?I will open a PR once the shape is agreed.
Checks
> AGENT GENERATED.