Skip to content

feat(bestie): a Bestie tab on your Bestie's agent page - #2034

Open
rileycrane wants to merge 4 commits into
mainfrom
rileycrane/bestie-l1-tab
Open

rileycrane wants to merge 4 commits into
mainfrom
rileycrane/bestie-l1-tab

Conversation

@rileycrane

@rileycrane rileycrane commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Your Bestie gets a Bestie tab on its agent page, and no other agent does. The tab says "This is your Bestie", has Change to pick another agent, and lists Bestie's settings, which later PRs in this stack fill in.

Why a tab: Bestie's settings live in a plugin tab that shows only on the agent it applies to, and each setting is stored in the thing it changes (instructions, timers, channel membership).

What changes

  • Host: a plugin's agent tab can pass an optional when(agent) filter, plus subscribe so the host re-checks it. That touches features/agents/service.ts and tabs.tsx. Tabs that set no filter, such as Watching, behave exactly as before.
  • Choosing a Bestie: the Make my bestie choice moves out of AgentsPage.tsx into BestieChoice.tsx, so the tab's Change reuses it, including the confirm-before-replace dialog.
  • Saved Bestie: default-agent.ts gains savedAgentStore, useSavedAgent for use outside React. With no window (node tests), it follows the account's choice only.
  • Layout: the tab is a size container, so its rows wrap to the agent side panel's width.

Try it (just dev)

  1. Open Agents, pick a local agent, then ⋯ → Make my bestie.
  2. Open that agent: it has a Bestie tab saying "This is your Bestie". Other agents have none.
  3. Click Change and pick another agent. After the confirm dialog, the tab moves to the agent you picked.
  4. Narrow the side panel: the rows wrap and nothing scrolls sideways.

Stack: each PR is based on the one before it: #2034 Bestie tab (this PR) → #2035 Remembers you → #2036 private channels → #2037 check-ins → #2039 Former Bestie → #2041 Remove as Bestie → #2047 Choose your bestie. #2040 (recent notes in Claude Code prompts) is separate and based on main.

Overlap: #1716 also changes features/agents/service.ts and tabs.tsx. Whichever lands second will rebase onto the other.

🤖 Generated with Claude Code

buzz-review-completed

rileycrane and others added 4 commits October 30, 2026 14:09
Plugin agent tabs take an optional `when(agent)`, and a `subscribe` that
tells the host when it may answer differently. Watching sets neither and
is unchanged. The Bestie plugin adds a Bestie tab to the agent saved as
your Bestie: "This is your Bestie", Change (which picks another agent and
opens the existing replace dialog) and read-only settings rows.

The replace dialog and its save logic move from AgentsPage into
BestieChoice so the Agents page and the tab share one path.

Co-authored-by: Opus 5.5 Max <d9fc2aa400ad81a2f289921a1720811e5d922c43e079f37241d4be458d8d92aa@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Riley Crane <rileycrane@squareup.com>
The saved choice's sources also fire for unrelated view state in the
community, such as drafts, which re-rendered every agents view.

Co-authored-by: Opus 5.5 Max <d9fc2aa400ad81a2f289921a1720811e5d922c43e079f37241d4be458d8d92aa@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Riley Crane <rileycrane@squareup.com>
The tab is its own size container, as each agent type's settings form
is, so its rows wrap their buttons to the panel's width and nothing
widens it.

Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Riley Crane <rileycrane@squareup.com>
The Bestie tab follows the saved agent as soon as it is registered. Outside
a browser, such as in the app runtime tests, following the device's choice
reached for window and stopped the Bestie plugin from starting. The README's
Bestie tab section is now part of Getting started, and the navigation test
counts the Bestie tab beside the Attention tab.

Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Riley Crane <rileycrane@squareup.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Star Lord’s automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

No actionable production defect found in this revision. The conditional tab reuses the saved-choice owner; account-save failures preserve the confirmation for retry, and the supported local-agent hosts observe the tab subscription updates. One optional host-level interaction-test suggestion is inline.

Reviewed head 89d58c10f7a8a1cdd57db00dba29badbc0422860, base 8fd0d34ae55e565e75cbc1fd31bc97897b0385be, PR merge-base 336e8a147dedf12034301ccaa57d471f119dd906. Inspected the 13-file PR delta, relevant callers/contracts, public description (no attached images), and commit messages. Source-only: no tests, builds or app execution; native behavior, keyboard/screen-reader focus after success/cancel, layout and incremental test cost remain unverified. One hosted CI snapshot shows JavaScript (2/3) and CI required failed, browser jobs passed, and Windows validation skipped; the failure’s relationship to this change was not established. This COMMENT is not approval or a runtime-validation claim.

await vi.waitFor(() => expect(tab.when?.(bea)).toBe(true));
expect(tab.when?.(ada)).toBe(false);
// The host is told, so the tab moves without a reload.
expect(changed).toHaveBeenCalled();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Optional: exercise this transition through the actual agent-tab host as well. This test leaves Tab mounted and verifies when/notification callbacks, whereas the real host removes the old Bestie section after a successful Change and selects its fallback section (AgentTabs.tsx). A host-level case for success, cancel and failed-save retry would verify the resulting selection and focus when the dialog/menu trigger disappears. Source review did not establish a focus-loss defect, so this is a validation suggestion rather than a required fix.

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