Skip to content

Open any Inbox filter view by route - #2394

Merged
Maxwellimus merged 7 commits into
mainfrom
maxwell/inbox-route-filters
Nov 4, 2026
Merged

Maxwellimus merged 7 commits into
mainfrom
maxwell/inbox-route-filters

Conversation

@Maxwellimus

@Maxwellimus Maxwellimus commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Why

The Inbox page opens with filters from a versioned route, but today that route only accepts { attention?: "unread", activity? }, the shape the ⌘⇧A/T/M/K shortcuts use. A plugin or buzz:// link can open Threads, Mentions, DMs or Unread, but it can't open Archived, Drafts, or a People/Agents sender filter. The only way to reach those is clicking through the filter menu.

This came up while building a sidebar plugin that pins Inbox views (Threads, Archived, Drafts, From agents and so on). It uses the shipped sidebar-section API, and its unsupported pins show "Needs a newer Buzz" until a route like this lands.

What

  • The Inbox route also accepts show: "inbox" | "archived", sender: "everyone" | "humans" | "agents", attention: "all" | "unread", or { drafts: true } on its own.
  • buzz:// links spell Drafts route.drafts=true, since link values are strings.

How

  • Omitted fields keep the saved choice, as before. A filter route still shows Inbox unless it names show: "archived", so the existing shortcuts behave the same.
  • A Drafts route opens Drafts and changes no saved filter.
  • A route that switches Inbox/Archived, or enters or leaves Drafts, clears the selection and cancels a pending Retry, like the filter menu does.
  • When a route swaps the Drafts surface, focus returns to the filter button, but only if focus was inside the Inbox page or its open filter menu. A fresh open into Drafts leaves focus where navigation put it.
  • The route's accepted values are keyed by the ShowFilter, SenderFilter and ActivityFilter unions, so adding a value to one fails to compile until the route accepts it.
  • Drafts is still not kept across a remount or Back/Forward. That is existing behavior when Drafts is chosen from the menu, too, so it stays out of this PR.

Risk

Low. The change is limited to src/bundled/inbox. Routes that were valid before parse and apply the same way, and a plain open without a route is unchanged.

Testing

Manual steps (human test still pending):

  1. Run Buzz from this branch and open a community.
  2. Open each link and check the Inbox filter summary:
    • buzz://plugin?id=buzz.inbox&page=inbox&route.show=archived → Archived.
    • buzz://plugin?id=buzz.inbox&page=inbox&route.sender=agents → Inbox, sender Agents.
    • buzz://plugin?id=buzz.inbox&page=inbox&route.drafts=true → Drafts.
  3. In Drafts, click the filter button to put focus there, press Escape, then press ⌘⇧T. Threads opens and focus stays on the filter button.
  4. Press ⌘⇧A, ⌘⇧T, ⌘⇧M and ⌘⇧K. Each works as on main.

Agent check: the pinned-shortcuts plugin, previewed against this branch, opened the Archived, Drafts and From agents pins in the right views with no page errors.

Generated with Claude Code

Maxwellimus and others added 5 commits November 3, 2026 21:46
The Inbox route accepts `show` (Inbox or Archived), `sender`, and
`attention: "all"` as well as `"unread"`, and `{ drafts: true }` on its own.
A link or plugin can now open any view the filter menu can show, including
Archived, Drafts, and People or Agents only. Omitted filters keep their saved
choice, as before. A route that switches between Inbox and Archived ends the
current selection, as the menu does, so the Archive shortcut never acts on a
conversation the list no longer shows.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
…oute

buzz://plugin links carry every route value as a string, so the route
accepts drafts "true" as well as true. Entering or leaving Drafts by
route now cancels a captured Inbox action, as the filter menu does.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
Like the menu, a route that enters or leaves Drafts refocuses the filter
trigger when the swapped surface dropped focus to the body, and leaves
focus elsewhere alone.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
A fresh Inbox opened on Drafts leaves focus where navigation put it; a
route swap refocuses the filter trigger only if focus was in the page.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
@Maxwellimus
Maxwellimus marked this pull request as ready for review November 4, 2026 09:06
@Maxwellimus
Maxwellimus requested a review from a team as a code owner November 4, 2026 09:06

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Approving. No blocking findings.

P3 (non-blocking) src/bundled/inbox/route.ts:22: the filters value lists are typed Record<string, readonly JsonValue[]>, so nothing ties them to ShowFilter, SenderFilter or ActivityFilter. If a value is later added to one of those unions, routes using it will be rejected without any error until this table is edited too. Typing the table against the unions (for example with satisfies { [K in keyof Filters]: readonly Filters[K][] }) would let the compiler catch the mismatch.

Verified at 31567a8: vitest run src/bundled/inbox (243 tests passed), tsc --noEmit and biome check src/bundled/inbox are clean.

Maxwellimus and others added 2 commits November 4, 2026 10:36
A value added to ShowFilter, SenderFilter or ActivityFilter now fails to
compile until the route accepts it, instead of being rejected silently.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
The menu portals outside the page, so a shortcut used while it had
focus in Drafts dropped focus to the body instead of the trigger.

Co-authored-by: Claude <[email protected]>
Signed-off-by: Max Lampert <[email protected]>
@Maxwellimus

Copy link
Copy Markdown
Contributor Author

🤖 Fixed the P3 in 213fe18. Each filter's accepted values are now keyed by its union (Record<ShowFilter, true> and so on), and the table is typed { [K in keyof Filters]: Record<Filters[K], true> }. I didn't use the satisfies readonly Filters[K][] form because a list that leaves out a new value still satisfies it. With the keyed version, removing agents fails with TS2741 ("Property 'agents' is missing").

In c9ea354 I also fixed a related focus gap that came up while re-reviewing. If a shortcut left Drafts while the filter menu was open, focus fell to the page body, because the menu portals outside the page. Focus now returns to the filter button, and a test covers it.

@Maxwellimus
Maxwellimus merged commit 801db19 into main Nov 4, 2026
41 checks passed
@Maxwellimus
Maxwellimus deleted the maxwell/inbox-route-filters branch November 4, 2026 19:39
michaelneale added a commit that referenced this pull request Nov 4, 2026
* origin/main:
  Open any Inbox filter view by route (#2394)
  fix(bestie): deleting an agent saves no Bestie record where there was none (#2420)
  fix(unread): never treat agents-audience messages as unread (#1552)
  feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277)
  [5/5] Add protection to the Goose harness plugin (#839)
  feat(agents): identify plugins in native hook output (#2299)
  [4/5] Add protection to the Codex harness plugin (#1879)
  feat(search): show member counts on channel results (#2333)
  Fix the mute icon flashing when selecting a channel (#2287)
  feat(agents): open a working agent's transcript from its activity (#2276)

Signed-off-by: Michael Neale <[email protected]>

# Conflicts:
#	crates/plugin-manager/tests/management.rs
#	src/app/pages.integration.test.mjs
#	src/features/agent-harness/acp/process.ts
wpfleger96 added a commit that referenced this pull request Nov 4, 2026
…-service

* origin/main:
  feat(plugins): let local agents write and reload plugins (#2435)
  feat(onboarding): offer Create a community after public Builderlab sign-in (#2397)
  Open any Inbox filter view by route (#2394)
gilgtm added a commit that referenced this pull request Nov 4, 2026
* origin/main: (22 commits)
  feat(mentions): quieter mention menu that marks agents and their owners (#2328)
  feat: add a Canvas View tab, History diffs and a 256 KiB limit (#2318)
  feat(plugins): let local agents write and reload plugins (#2435)
  feat(onboarding): offer Create a community after public Builderlab sign-in (#2397)
  Open any Inbox filter view by route (#2394)
  fix(bestie): deleting an agent saves no Bestie record where there was none (#2420)
  fix(unread): never treat agents-audience messages as unread (#1552)
  feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277)
  [5/5] Add protection to the Goose harness plugin (#839)
  feat(agents): identify plugins in native hook output (#2299)
  [4/5] Add protection to the Codex harness plugin (#1879)
  feat(search): show member counts on channel results (#2333)
  Fix the mute icon flashing when selecting a channel (#2287)
  feat(agents): open a working agent's transcript from its activity (#2276)
  test(agents): refuse a real relay workflow mention in the harness kit (#2444)
  fix(agents): catch up every event watch on the kinds it watches (#1852)
  Keep local artifact collections current (#1507)
  feat(members): add several people to a chat in one write (#2010)
  feat(solo): let viewers join read-only spaces (#2301)
  [3/5] Add protection to the Claude harness plugin (#1878)
  ...

Signed-off-by: Gil Birman <[email protected]>
Co-authored-by: Claude <[email protected]>
wpfleger96 added a commit that referenced this pull request Nov 4, 2026
…r-load-perf

* origin/main:
  Open any Inbox filter view by route (#2394)
  fix(bestie): deleting an agent saves no Bestie record where there was none (#2420)
  fix(unread): never treat agents-audience messages as unread (#1552)
  feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277)
  [5/5] Add protection to the Goose harness plugin (#839)
  feat(agents): identify plugins in native hook output (#2299)
  [4/5] Add protection to the Codex harness plugin (#1879)
  feat(search): show member counts on channel results (#2333)
  Fix the mute icon flashing when selecting a channel (#2287)
  feat(agents): open a working agent's transcript from its activity (#2276)

Signed-off-by: Will Pfleger <[email protected]>

# Conflicts:
#	src/features/agent-harness/acp/agent-sessions.ts
wpfleger96 added a commit that referenced this pull request Nov 4, 2026
…-nip-fi

* origin/main: (23 commits)
  fix(inbox): show Solo responses under All, read live replies in the open conversation, describe toolbar badges (#2275)
  AIDA-2434: Show saved teams in mentions (#2339)
  AIDA-2455: Restore channel scrollbar dragging beside threads (#2436)
  feat(agent-protection): show the owner why a protection provider denied input (#2105)
  fix(search): show slow lookups beside their section headings (#2442)
  Align Bestie DM layout and unread state; speed up thinking shimmer (#2418)
  Send Claude, Pi and Goose history as exact records (#2088)
  fix(agent-activity): align the stopped note and show it after the agent's reply (#2441)
  fix(agents): stop orphaned Attention commands and prevent duplicate runs (#2448)
  feat(mentions): quieter mention menu that marks agents and their owners (#2328)
  feat: add a Canvas View tab, History diffs and a 256 KiB limit (#2318)
  feat(plugins): let local agents write and reload plugins (#2435)
  feat(onboarding): offer Create a community after public Builderlab sign-in (#2397)
  Open any Inbox filter view by route (#2394)
  fix(bestie): deleting an agent saves no Bestie record where there was none (#2420)
  fix(unread): never treat agents-audience messages as unread (#1552)
  feat(focus): add an optional Focus plugin that quiets everything except Solo chats (#2277)
  [5/5] Add protection to the Goose harness plugin (#839)
  feat(agents): identify plugins in native hook output (#2299)
  [4/5] Add protection to the Codex harness plugin (#1879)
  ...

# Conflicts:
#	src/features/identity/builderlab-hosted.test.ts
#	src/features/identity/builderlab-hosted.ts
tulsi-builder added a commit that referenced this pull request Nov 5, 2026
## Why

People said Inbox's filter bar was crowded and Archive didn't make
sense. They liked the tabs and the Unread toggle, and they wanted the
page called **Activity**, like Slack's. This PR keeps those parts and
removes the rest, so the toolbar fits on one row for as long as
possible.

## What

- **Rename:** Inbox is now **Activity**, in the page title, the sidebar
row, the shortcut titles ("Open … in Activity") and the help docs. The
bell icon stays. Plugin id `buzz.inbox`, page id `inbox` and storage
keys are unchanged.
- **Toolbar:** one left-aligned row.
- Type tabs come first: All, Threads, Mentions, DMs. The first tab lines
up with the title-bar bell.
- A text-only **From** menu (Anyone / People / Agents) follows the tabs.
It gets a subtle fill while it's narrowing the list.
- The **Unread** switch sits right after From, so it stays in view on a
full-width page.
- When the window is too narrow, Unread wraps to the next line first,
then From.
- **Archive removed:** every conversation stays in the list. The row ✓
is now **Mark as read**. It only shows on unread rows.
- With Unread on, the row leaves the list and an **Undo** toast appears.
- When nothing unread is left, the list says **All caught up** and
offers **Show all**.
- **Drafts removed:** a draft stays in the conversation where it was
written.
- **Focus:** after Mark as read, focus moves to the next row only if
focus is still in the list. If someone moves to the composer while the
read is still saving, their cursor stays where they put it.
- **Sidebar hover card (#2347):** now titled Activity, with an **Open
Activity** button. It no longer hides conversations that were archived
before, so it lists the same conversations as the page.
- **Filter routes (#2394):** the route contract drops `show` and
`drafts`. Older links that still carry them open the page with its saved
filters instead of failing: `show` is ignored, and `{ drafts: true }`
alone opens the saved filters.

## Screenshots

<!-- Default toolbar · From menu · From: People · Marked as read + Undo
· All caught up · Narrow (560px) · Hover card -->

## Not in this PR

- The Inbox badge and bold label: #2337.
- Which items count as unread: #2401.
- The unread logic from #2275.
- "Retry inbox" and "Inbox history unavailable" in
`src/features/relay/session.ts` and `inbox-feed.ts`. Those files are
shared relay code, so the strings are unchanged.
- `archive.ts` no longer has a caller in the page or the card. Removing
it is a follow-up, so this PR doesn't touch the files #2275 edited.

## Testing

- **Unit:** `vitest run src/bundled/inbox src/app src/features/pages
src/plugins` passes, 1347 tests after the latest rebase.
- New: Mark as read via the ✓ and via the context menu, each when the
save succeeds and when it fails. In all four, focus stays in the
composer the user moved to. All four fail without the fix.
- New: route cases for sender-only routes and links that still carry
`show` or `drafts`.
- **Browser, Chromium and WebKit:** `tests/browser/inbox*` and
`sidenav-polish` pass, 74 tests after the latest rebase.
- New `inbox-mark-read.spec.mjs` covers the one-row toolbar layout, bell
alignment, Mark as read with Undo, and All caught up.
- **Static checks:** `tsc`, `lint` and `design:check` are clean.
- **Agent review:** Crack Catcher's blocking finding was a focus jump
during a pending read. It's fixed, and Crack Catcher confirmed it.
- **Human testing:** tulsi tried it in the desktop dev app and confirmed
it all works.

buzz-review-completed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<img width="1280" height="800" alt="1 Default toolbar"
src="https://github.com/user-attachments/assets/4e3d23ac-5529-48b6-ab91-594ce3933e52"
/>
<img width="1280" height="800" alt="2 From menu open"
src="https://github.com/user-attachments/assets/7e2c86df-998a-467d-9ae8-10ea8c73bcbc"
/>
<img width="1280" height="800" alt="3 From People (dark)"
src="https://github.com/user-attachments/assets/3dd58da4-204b-46de-b4e5-cc531f7bd580"
/>
<img width="1280" height="800" alt="4 Marked as read with Undo"
src="https://github.com/user-attachments/assets/d54214a4-2990-4080-bf1d-15d6cacfd4fc"
/>
<img width="1280" height="800" alt="5 All caught up"
src="https://github.com/user-attachments/assets/215850bb-8ed3-49c4-a4a7-a7cf6e2530ff"
/>
<img width="560" height="800" alt="6 Narrow window"
src="https://github.com/user-attachments/assets/e4a1fa0c-a19e-45de-b082-43c5295f7cba"
/>
<img width="1280" height="800" alt="7 Hover card"
src="https://github.com/user-attachments/assets/63947445-59ae-4c49-97b4-d04ae12c6875"
/>

---------

Signed-off-by: tulsi <[email protected]>
Co-authored-by: BasilBot <399581b6165ab01343e3a1324774b1024d76942aea563468f93c975e5ee5193c@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants