Skip to content

feat(bestie): Choose your bestie when there's none, and clear a deleted Bestie - #2047

Draft
rileycrane wants to merge 22 commits into
rileycrane/bestie-l6-removefrom
rileycrane/bestie-l7-empty-state
Draft

rileycrane wants to merge 22 commits into
rileycrane/bestie-l6-removefrom
rileycrane/bestie-l7-empty-state

Conversation

@rileycrane

@rileycrane rileycrane commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

When there's no Bestie, the Bestie page offers Choose your bestie: pick one of your agents or create one. If you delete your Bestie, the account is set to none, so the page shows the chooser instead of an agent that's gone. For now only agents on this device are offered.

This branch includes #1935 (clay/bestie-pinned-nav, merged at ce6734793 in 1ffa2e59b). It will be rebased once #1935 merges. Review only the commits listed below; the merge commit is listed for context only.

Commits to review

  • eb45012e5 feat(bestie): choose an existing agent or create one. This ports the ChooseBestie component from feat(bestie): pin the saved Bestie DM #1935's earlier head (ce6734793..f78963029) onto the stack. The stack keeps its Bestie and Former Bestie tabs, check-in cleanup, and remembers-on.
  • 6c2e161e8 feat(bestie): offer local agents in place, and remember from the sidebar.
  • f5a7c875e feat(bestie): deleting your Bestie saves none to the account.
  • cd653c6fc fix(bestie): clear a deleted Bestie once the account is read, and turn away a hosted agent made here.
  • b024c3c57 test(bestie): expect Choose your bestie on the empty Bestie page. plugin-defaults and sidenav-polish waited for the old "Meet your Bestie" heading.
  • For context only: 1ffa2e59b merges feat(bestie): pin the saved Bestie DM #1935. The conflicts in the README, index.tsx and default-agent.ts were resolved to keep both sides.

What changes

  • Choose your bestie. The empty Bestie page lists your agents and has New agent. It says "Only agents on this device can be your Bestie for now." Hosted agents aren't listed. If you create a hosted agent from this page, it isn't made Bestie, and the page says why.

  • No longer here. If the saved Bestie isn't one of your agents anymore, the pinned Bestie says "Zed is no longer here. Choose another agent to be your bestie." The same chooser is shown in place, so you don't have to leave the page.

  • Deleting your Bestie saves none. It clears only if the account still holds that agent's pubkey, using the null writer from feat(bestie): remove your Bestie, and only local agents can be Bestie for now #2041. It saves nothing in these cases:

    • another device has chosen a different Bestie;
    • a choice made here is still saving.

    If the account hasn't been read yet, the delete is remembered and the clear happens when the read returns that pubkey.

  • A choice from the sidebar (chooseBestie) fires onBestieMade, so remembers-on applies to it as well as to the Bestie tab.

Try it (just dev)

  1. Use a fresh account, or Remove your Bestie (feat(bestie): remove your Bestie, and only local agents can be Bestie for now #2041). The Bestie page shows Choose your bestie. Pick a local agent: it becomes your Bestie, with Remembers you on.
  2. Delete that agent. The Bestie page shows Choose your bestie again, not a ghost of the deleted agent.
  3. If you have a hosted agent, it isn't in the list.

Checks

  • tsc, biome --error-on-warnings and design:check pass.
  • vitest: 103 files, 1853 tests passed, 1 skipped. This covers the bestie, agents and channels directories, solo, native-sidebar, session-main-agent, pages.integration, entity-navigation, readmes, BestieNavigation and ChannelInventory.
  • plugin-defaults.spec.mjs and sidenav-polish.spec.mjs pass 24/24 on chromium and webkit with the new heading.
  • New browser check tests/browser/bestie-choose.spec.mjs passes 4/4 (chromium and webkit). It renders the production Bestie page twice: with no Bestie, and with a Bestie that's no longer here. In both, it opens the chooser and confirms that the local agent is offered and the hosted one isn't.
  • An independent agent review was done. Its fixes are in cd653c6fc, each with a test that fails without it.

Known gaps

  • Read-then-write race. The clear reads the account and then writes; there's no compare-and-swap. Another device's choice made in that gap can be overwritten with none.
  • No retry. If the account read inside the clear fails, the clear isn't retried. It logs "The deleted Bestie wasn't cleared from your account".
  • Signed-out sessions. A session that has ended can stay in the list of accounts until it's collected. A delete in that window can log the same warning without effect.
  • A failed first choice keeps the choice unknown until the next successful save.
  • Dead hosted-setup code. setup.ts, prompt.ts and testing.ts are no longer used. They're left in place, as in f789630.
  • Fewer page tests. The port drops three page-level tests from index.test.tsx, as feat(bestie): pin the saved Bestie DM #1935's f789630 does. PinnedBestie's chooser test checks that the chooser appears, but doesn't pick an agent.
  • Out of scope: matching pinned DMs, navigation and search, Catch me up, hosted agents.

The ChooseBestie port is co-authored by Clay Delk, from #1935.

Stack: each PR is based on the one before it: #2034 Bestie tab → #2035 Remembers you → #2036 private channels → #2037 check-ins → #2039 Former Bestie → #2041 Remove as Bestie → #2047 Choose your bestie (this PR). #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

delkc and others added 22 commits October 30, 2026 10:38
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Show the saved Bestie identity in page search while preserving Bestie as a searchable detail. Carry display owner metadata through directory results so agent namesakes use readable owner qualifiers before key suffixes.

Co-authored-by: Buzzsaw <a760f3ee1dc0daf403313e35766d0d983a8898aaa9ca95a034727165c63a8680@claysworld.communities.buzz.xyz>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Co-authored-by: Buzzsaw <a760f3ee1dc0daf403313e35766d0d983a8898aaa9ca95a034727165c63a8680@claysworld.communities.buzz.xyz>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Co-authored-by: Buzzsaw <a760f3ee1dc0daf403313e35766d0d983a8898aaa9ca95a034727165c63a8680@claysworld.communities.buzz.xyz>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
Signed-off-by: Clay Delk <clay.delk@gmail.com>
This reverts commit f789630.

Signed-off-by: Clay Delk <clay.delk@gmail.com>
Brings in Clay's pinned Bestie DM at ce67347. The Bestie plugin keeps both
sides: #1935's page and the stack's tabs, check-in cleanup and onBestieMade.
In the account's saved choice, #1935's read errors and revisions are kept
alongside the stack's known-choice tracking, and a successful save becomes
the value a later failed choice falls back to.

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>
Ports Clay's Choose your bestie from #1935's pre-revert head f789630: with
no saved Bestie, the Bestie page offers the viewer's eligible agents and the
shared New agent dialog in place of Builderlab's hosted setup. The plugin
keeps registering the stack's Bestie tabs, check-in cleanup and
onBestieMade alongside the page.

Co-authored-by: Clay Delk <clay.delk@gmail.com>

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>
Choose your bestie moves into its own chooser, which the page shows with no
saved Bestie and also in place of one that is no longer here. Like Change and
Make my bestie, it offers only agents on this device, and says so. A choice
made in it is saved through chooseBestie, which also tells onBestieMade, so a
Bestie chosen from the sidebar starts with Remembers you on too.

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>
A deleted agent that the account saved as main is cleared from the account
too, with the none writer that saves no Bestie, so the Bestie page shows
Choose your bestie rather than an agent that is gone. The account is read
again first, and is left alone if another device has chosen another agent
since, or if a choice made here is saving or was made during the read.

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>
…n away a hosted agent made here

- Deleting a Bestie before the account has been read now remembers the
  pubkey and saves none when the read comes back with it.
- A failed clear says the choice is known again.
- A later failed choice falls back to the saved choice, not an older read.
- An agent created from the chooser that isn't on this device is not saved
  as Bestie; the chooser says why.
- Browser check of the empty and no-longer-here pages: only local agents
  are offered.

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 empty Bestie page now offers Choose your bestie, not Meet your Bestie.
plugin-defaults and sidenav-polish open the page with no Bestie and wait
for its heading.

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>
@rileycrane
rileycrane force-pushed the rileycrane/bestie-l6-remove branch from 7b9426c to 4bca2e3 Compare October 30, 2026 23:24
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