镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

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

Merged
rileycrane merged 6 commits into
mainfrom
rileycrane/bestie-l1-tab
Nov 2, 2026
Merged

rileycrane merged 6 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

@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.

rileycrane and others added 4 commits November 2, 2026 10:26
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>
@rileycrane
rileycrane force-pushed the rileycrane/bestie-l1-tab branch from 89d58c1 to 0b8bbc3 Compare November 2, 2026 19:08

@loganj loganj 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.

🤖 Larry and Auto: an independent adversarial review of 0b8bbc3. Source review only: we read the code and did not run the app or the tests. Labels: error, convention, preference, advice, question. Must-fix items say so.

Verdict: approve. No must-fix items. The when/subscribe host change is correct: the tab registry has two consumers (AgentTabs.tsx, ProfilePanel.tsx), both go through agentSections, a throwing when hides only its own tab, and a selected tab that disappears falls back to the first tab / info. Moving useBestieChoice out of AgentsPage keeps its behavior.

  • convention: docs/agents.md:83 still says plugins "add a tab to every local agent". It should mention when.
  • advice: Change lists library agents that are not on this device, and choosing one makes the tab disappear. #2041 fixes this; it matters only if this PR ships alone.
  • preference: default-agent.ts:234 guards subscribeView with typeof window === "undefined" only for Node tests. Put the guard in subscribeView or in the tests, not in the production path.
  • advice, tests: the invariant is that the tab appears or disappears without a reload when the saved Bestie changes. No test mounts AgentTabs and changes the saved Bestie; the tests check snapshot identity and agentSections with a hand-made when.

error={error}
onClose={() => {
if (error) {
restoreDefaultAgent(

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.

advice: restoreDefaultAgent runs only from the dialog's close handler. chooseDefaultAgent caches the new choice on this device before account.write. If the write fails and the owner closes the side panel (not Keep), the dialog unmounts without a restore: this device's default is B, the account's Bestie is still A, and the error is lost. On the Agents page this was rare; a side-panel tab is easy to close. Restore on unmount, or cache only after the write succeeds.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🤖 Fixed in 70e2ee2. The device's choice is now put back when the dialog unmounts with a failed save, for example when you close the side panel instead of pressing Keep. It's also put back when a save that was still running fails after the panel closed. There are tests for both cases.

Comment thread docs/plugin-architecture.md Outdated
@@ -323,7 +323,11 @@ agent-record migrations; blank per-agent values inherit them.
A plugin, bundled or installed, can add a tab to the settings of every agent
running on this device, whatever its type, with
`ctx.agents.registerTab({ id, title, component })`. The component receives

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.

convention: the example still shows registerTab({ id, title, component }). Add when and subscribe so it matches the next sentence.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🤖 Fixed in aeaa862. The example now reads registerTab({ id, title, component, when, subscribe }), and docs/agents.md mentions when.

rileycrane and others added 2 commits November 2, 2026 14:39
Closing the side panel unmounts the replace dialog without its close
handler, so a failed account write left this device on the new Bestie
while the account kept the old one. A failed replacement is now
abandoned on unmount too, and one still saving abandons itself when it
fails after the panel has closed.

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>
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 added a commit that referenced this pull request Nov 2, 2026
A Claude Code agent now starts each session knowing what it wrote down
today and yesterday. Its prompt carries those daily notes
(`mem/notes/<date>`) next to core memory.

It is based on main and is independent of the Bestie tab stack (#2034
onward).

**What changes**
- `features/agent-harness/core-memory.ts` gains a helper next to core
memory. It reads yesterday's and today's notes by slug and keeps the
newest 8 KB of each.
- The Claude Code runtime adds a `<recent-notes>` block after core
memory, once per process start.
- A missing, blank or unread note adds nothing, and a start waits at
most 2 seconds for the notes. After that it cancels the reads, so they
don't hold up other agents' memory reads. A read another caller still
waits for keeps running.
- Dates follow the device's time zone, with UTC as the fallback.

**Trade-offs**
- An agent's process start now does one relay read. Before, it did none:
`launch-boundary.test.ts` loosens that invariant in three tests.
- A long-running process keeps the notes it read at start until it
restarts, including across midnight.
- Claude Code only. Codex, goose, Pi and hosted agents are not covered.

**Try it** (`just dev`, with a local Claude Code agent)
1. Ask the agent to save a note for today (`mem/notes/<today>`), for
example "I like short answers".
2. Restart the agent (or Buzz) and start a new chat. Ask it what today's
note says. It answers without reading memory first.
3. An agent with no daily notes behaves as before.

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

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@rileycrane
rileycrane merged commit 9dae5ca into main Nov 2, 2026
41 checks passed
@rileycrane
rileycrane deleted the rileycrane/bestie-l1-tab branch November 2, 2026 23:24
dr0uleau added a commit that referenced this pull request Nov 2, 2026
Co-authored-by: Codex <noreply@openai.com>

* origin/main: (26 commits)
  AIDA-2336: Show when worktree folders are required (#2165)
  AIDA-2326: Reveal full emoji completion names (#2172)
  feat(agent-command): let local agents discover advertised plugin tools (#2110)
  feat(bestie): a Bestie tab on your Bestie's agent page (#2034)
  fix(relay): notify verified profile changes once per replay (#2209)
  feat(shortcuts): open Shortcuts settings with Mod+/ (#2022)
  Re-send live channel subscriptions on access grants, not every minute (#2207)
  perf(profiles): count verified namesakes once per publish (#2159)
  feat(claude-code): start sessions with the agent's recent notes (#2040)
  fix(relay): skip status, emoji, read-state and reminder re-reads a continuous replay covers (#2204)
  Support agent credentials through the macOS debug helper (#2174)
  refactor: centralize relay search debounce and require two characters (#2200)
  fix(relay): drop unused profile exemptions from config and agent reads (#2202)
  fix(relay): skip full profile and roster re-reads after a continuous reconnect (#2203)
  Notify when Solo chat agents finish (#2011)
  feat(mcp): start a Solo chat with channel_create (#2128)
  fix(relay): keep profiles when channel access ends (#2187)
  Wait for thread readiness before keyboard input (#2181)
  fix(builderlab): unify the development sign-in (#2109)
  feat(host): add byte requests, private saves and POST dispatch protection (#2084)
  ...

Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
rileycrane added a commit that referenced this pull request Nov 2, 2026
The Bestie tab gets **Remembers you**: a switch that adds memory rules
to the agent's instructions, and removes them when turned off.

**Why it works this way:** the memory rules are a marked, versioned
section of the agent's own instructions, so the owner can read and edit
them, and later features can add sections the same way.

**What changes**
- **On** adds a section marked `<!-- buzz:bestie/memory v1 -->` … `<!--
/buzz:bestie/memory -->` to the instructions. **Off** removes it. No
memory is deleted: core memory is still in every prompt, and the Memory
tab still clears memory.
- **The switch follows the markers.** It stays on through the owner's
edits inside the section. Off keeps any text the owner put before or
after the markers.
- **Edited markers.** If a marker is edited, removed or copied, the row
says the section was edited instead of showing a switch, so it never
adds a second section. **Restore** puts the original back when the
markers still show where the section is.
- **Feature list.** `features.ts` holds the feature list. Memory is its
first entry; check-ins (#2037) add one more.

**Design decisions**
- On and Off save the agent's instructions through `agents.save`; the
next turn uses them. Rejected: a hidden section the host adds to every
prompt.
- An edited section blocks On rather than guessing. Rejected: rewriting
the owner's edits.

**Try it** (`just dev`, with a local agent that is your Bestie)
1. Open its **Bestie** tab and turn **Remembers you** on. Open
**Instructions**: the marked memory section is at the end.
2. Type a line inside the section and save. The switch stays on.
3. Turn it off. The section is gone, and the text you wrote outside it
stays.
4. Delete one marker in Instructions. The row says the section was
edited, with **Restore**. Click **Restore** to put the section back.

**Stack:** each PR is based on the one before it: #2034 Bestie tab →
**#2035 Remembers you (this PR)** → #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](https://claude.com/claude-code)

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
delkc added a commit that referenced this pull request Nov 3, 2026
## Why

The pinned Bestie DM from #1935 needs a clear starting point when no
Bestie is saved. The old page instead launches a separate Builderlab
setup flow. This replaces that path with one chooser for existing agents
and new agents.

## What

- Explain what a bestie means, then offer a searchable picker with
avatars, names, and distinct identity labels.
- Open the picker below its field, capped at roughly four avatar rows,
with search above scrollable results.
- Reuse **Create agent**, save the choice to the account, and open the
canonical DM.
- Keep remote agents eligible, but ask before saving: “Some bestie
features aren’t available with remote agents.” Cancel leaves the choice
unchanged and keeps any newly created agent.
- Show the chooser in place when the saved agent is gone, and clear the
account choice after completed deletion.

## How

The chooser uses `session.agentChoices`, the shared creation dialog, the
existing `main-agent` record, and the pinned DM from #1935. It adds no
messaging path or remote capability setup. The shared Combobox gains an
opt-in compact popup; other callers keep their current behavior.

Deletion checks the current account record before writing `agent: null`.
Native signing now admits that cleared value. Existing browser journeys
retain their plugin/default and navigation contracts with the new
heading; browser cases added/removed: **0/0**. The retired hosted-setup
UI assertions are replaced by mounted chooser/save/recovery coverage.

## Risk

This removes the separate Builderlab-specific Bestie onboarding, not
Builderlab agent creation. The remote warning does not turn on memory or
check-ins. Account cleanup is a read/replace, not an atomic
compare-and-swap: another device's choice in that gap can be
overwritten. A cleanup error reports that deletion completed but the
Bestie choice could not be cleared.

## Testing

Clay tried the running native app and iterated on the empty-state copy,
searchable picker, and popup size/placement. The remote confirmation was
opened through the production chooser in an isolated Chromium fixture
with a sample hosted agent; no real agent was created or account choice
saved.

Still deferred: live Builderlab creation → confirmation → account save →
DM; deletion and reload persistence on the rebased head; native
remote-warning focus behavior; and the full light/dark, viewport, and
enlarged-text acceptance pass. These checks remain outstanding; this PR
does not claim completed acceptance.

## Bigger picture

#1935, Riley’s Bestie tab (#2034), and its memory switch (#2035) are
merged. This branch includes main through `23338bc84`, preserving both
alongside the empty-state chooser.

**Overlap with Riley's #2047:** both replace the empty Bestie page and
clear a deleted choice. This PR contains the chooser UI Clay tested
today. Riley's PR sits above the Bestie settings/memory/check-in stack,
restricts Bestie to local agents, and wires selection into that setup.
This PR deliberately allows remote agents with a warning. The tab and
memory switch have landed independently. This chooser remains compatible
with both; later check-in and setup work must preserve the remote-agent
policy. That follow-up must reconcile the duplicate chooser/deletion
work and handle nonlocal capabilities without silently restoring a
local-only restriction. No changes to Riley's branches are included
here.

Generated with Goose

---------

Signed-off-by: Clay Delk <clay.delk@gmail.com>
Co-authored-by: Buzzsaw <a760f3ee1dc0daf403313e35766d0d983a8898aaa9ca95a034727165c63a8680@claysworld.communities.buzz.xyz>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Goose <goose@block.xyz>
rileycrane added a commit that referenced this pull request Nov 3, 2026
The Bestie tab lists the private channels you share with Bestie. From
the tab you can add Bestie to one channel or to all your private
channels, and remove it from any of them.

**Why only private channels:** agents can already read public channels,
so only private channels need Bestie added.

**What changes**
- **Private channels Bestie can read:** each channel is listed with
**Remove**, which asks first, as the Members dialog does.
- **Add to a channel** (**Choose…**): a picker of your private channels
that don't have Bestie yet, most recently active first.
- **Add to all my private channels:** adds Bestie to every private
channel you're in that doesn't have it.
- Adds and removes are the same NIP-29 membership events the Members
dialog sends (kinds 9000/9001). After each one, the tab reads the roster
again to confirm. Remove and the config channels share one helper for
this, `administerMember` in `channel-members/administration.ts`.
- **Bestie joins as a guest**, so it reads the channel but can't post
there. `memberAdditions.add` takes an optional `{ role: "guest" }` for
this; every other addition keeps the role it had.
- **The browser host signs guest invitations**: its kind 9000 allowlist
now accepts `role=guest`, as well as no role or `role=member`. Owner,
admin and bot stay out of it.
- **An addition finishes only with the role it asked for** (shared with
the Members dialog and Outbox): an add already running, or a saved
receipt for the same channel and person, is reused only for the same
role. Otherwise the add stops with an error that says to retry or remove
the receipt in Outbox. No second write competes with it, and the receipt
stays. So a Members-dialog add no longer sends a new write past a saved
guest receipt, and Outbox **Retry** retries a guest addition as a guest.
- **Until the channel list has loaded in full**, the section says so
instead of saying Bestie is in none. A failed read shows **Retry**,
which reads the list again. The channels already known keep their rows,
and **Add to all** waits for the full list. A channel known only from a
cached list offers no Add or Remove until it is read again.
- **Keyboard focus stays in the section** when its control leaves: after
a Remove drops its row, or the last add takes **Choose…** and **Add to
all** with it, focus moves to the control now in its place, or to the
section heading. Focus you already moved elsewhere stays there.
- Each action has its own row, so in a narrow panel its button wraps
under the label.
- **Changing your Bestie stops an Add to all under way**, so the old
Bestie isn't added to the channels left.

**Try it** (`just dev`, with a local Bestie and two private channels it
isn't in)
1. Open the **Bestie** tab. Under **Private channels Bestie can read**,
click **Add to a channel → Choose…** and pick one channel. That channel
appears in the list, and its timeline shows that you added Bestie.
2. Click **Add to all**. The other channel is added too.
3. Click **Remove** on one channel and confirm. It leaves the list. With
the keyboard, focus moves to the next row.

**Stack:** each PR is based on the one before it: #2034 Bestie tab →
#2035 Remembers you → **#2036 private channels (this PR)** → #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](https://claude.com/claude-code)

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rileycrane added a commit that referenced this pull request Nov 3, 2026
The Bestie tab gets **Check-ins → Every hour**. Turned on, it wakes your
Bestie in your DM once an hour.

**Why a local timer:** a Bestie on this device is woken by a timer on
this device, using the same Attention timers as the Watching plugin.

**What changes**
- **Every hour** needs **Remembers you**. It is disabled while memory is
off, and turning memory off turns it off too.
- **On:**
- Adds an Hourly upkeep section (`buzz:bestie/checkin.hourly`) to the
instructions. Each check-in reads what's new in your DM and in the
private channels Bestie was added to, and reports only in the DM.
- Saves an hourly Attention timer, `watch/bestie-hourly-check-in`,
through `agents.save`; the timer wakes Bestie in your DM.
  - Turns on the agent's Attention.
- **Off** removes the section and the timer. It leaves Attention on,
because the agent's other watches may need it.
- The timer runs while Buzz is open and Watching is on. While it can't
run, the row says **Paused**. A timer paused in the Attention tab, which
can't resume it, says **Paused in Attention** and how to restart it;
**Off** still works. After a sleep it runs once, not once for each
missed hour.

**Design decisions**
- No `controlAttention()`. Turning Watching off still stops every
agent's Attention, so Bestie doesn't take over a control the user can
see. Rejected: having the plugin turn Attention on through
`controlAttention()`.
- The timer is saved first, then the instructions, so a failed save
leaves no section without a timer. If the instructions fail to save,
**On** undoes the timer, and turns Attention back off only if it turned
it on. If that undo fails too, a row says the timer is still saved and
offers **Remove**.

**Try it** (`just dev`, local Bestie with Remembers you on)
1. Turn **Every hour** on. The Watching tab shows the timer
`watch/bestie-hourly-check-in`, and Instructions has the Hourly upkeep
section.
2. Turn **Remembers you** off. **Every hour** turns off and is disabled.
3. Turn memory back on, then check-ins on, then disable the Watching
plugin. The row says it is paused.

**Stack:** each PR is based on the one before it: #2034 Bestie tab →
#2035 Remembers you → #2036 private channels → **#2037 check-ins (this
PR)** → #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](https://claude.com/claude-code)

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rileycrane added a commit that referenced this pull request Nov 3, 2026
…ie tab (#2039)

When you change your Bestie, the old one stops checking in, and its
other settings stay where you can reach them in a **Former Bestie** tab.

**Why:** only one agent should check in on you. A former Bestie's other
settings (memory, channels) are still on, so they stay reachable in
their own tab instead of becoming invisible.

**What changes**
- **Only your Bestie checks in.** Whenever the saved Bestie is known,
every other local agent has its check-in section and timer removed. Its
memory section and channels stay. A choice made on another device counts
once this device next reads the account, once per connection.
- **Former Bestie tab:** it shows "<name> is no longer your Bestie.
These are still on.", the same switches, **Remove from all** for its
private channels, and **Make my Bestie again**. The tab shows while the
agent has a Bestie section or, if this device saw it as Bestie, while it
is in one of your private channels.
- **New Bestie starts remembering.** An agent this device makes Bestie
starts with Remembers you on (the plugin hears `onBestieMade`). A choice
synced from another device changes nothing, so memory turned off stays
off.
- **Tests:** a browser layout check (`tests/browser`) covers the Bestie
and Former Bestie tabs at two panel widths and two text sizes.

**Design decisions**
- Cleanup acts only on a Bestie the account has saved. While the account
is still being read, nothing is removed.
- Turning the Bestie plugin off stops a cleanup already under way: it
saves nothing more, not even the instructions after a timer save, and
starts no further pass.
- Former Bestie is a second tab (`buzz.bestie/former-bestie`), not a
mode of the Bestie tab, so each tab's `when` stays simple.

**Try it** (`just dev`, with two local agents, Ada as Bestie with
Remembers you and Every hour on)
1. In Ada's **Bestie** tab, **Change** to Bea and confirm.
2. Ada now has a **Former Bestie** tab: Remembers you is still on, Every
hour is off, and its timer is gone from Watching.
3. Bea has the **Bestie** tab, with Remembers you on.
4. In Ada's Former Bestie tab, click **Make my Bestie again** and
confirm. Ada has the Bestie tab again.

**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 (this PR)** → #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](https://claude.com/claude-code)

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
rileycrane added a commit that referenced this pull request Nov 4, 2026
…er a warning (#2041)

You can **Remove** your Bestie, so the account saves none. Once the
account is read to have saved none, check-ins stop on every local agent.
A remote agent, hosted or on another device, can now be your Bestie from
every place that offers one, after the same warning the empty-state
chooser shows.

Check-ins stop when you save no Bestie, just as they do when you change
it (#2039). An account that never chose a Bestie changes nothing.

> **The `main-agent` record** (kind 30078, `d=main-agent`, added in
#1665). Saving `agent: null`, the native signer's admission of it, and
the conditional clear after deletion are already on main (#2173). This
PR changes only the reader: it returns `null` for a record of none and
`undefined` when there is no record, where before it read both as no
choice. It also writes a record of none on an account that has no record
yet, though that matches the empty value, so other devices read it as a
choice. The record shape is unchanged.

**What changes**
- **Remove as Bestie.** A row on the Bestie tab under Change, with
**Remove**. It asks first: "Remove Ada as your Bestie?" The dialog's
focus starts on Cancel. If the save fails, the error shows in the dialog
and the Bestie stays. There is no Remove without an account (device-only
session), because the composer would pick another agent at once. Remove
uses main's `clearDefaultAgent`.
- **Cleanup with no Bestie.** Once the account is read to have saved
none, every local agent's check-in is stopped. An account with no record
stops nothing. While the read is pending or has failed, or while a
choice made here is still saving, nothing is stopped either. The Former
Bestie tab follows the same rule.
- **Remote agents can be Bestie.** Change, Agents → **Make my bestie**
and the Former tab's **Make my Bestie again** offer every eligible
agent, remote ones included. Before a remote agent is saved, they ask
with the empty-state chooser's own confirmation, now one shared
`RemoteBestieConfirm`: "Use Sky as your bestie? Some bestie features
aren't available with remote agents." Cancel saves nothing. When a
remote agent would replace a saved Bestie, the replacement dialog asks
once and adds that sentence. A remote Bestie's switches show "Not
available with remote agents yet.", and it doesn't start with Remembers
you on. Check-in cleanup still stops only agents on this device, so
changing from a local Bestie to a remote one still stops the local
agent's check-ins.

**Design decisions**
- **A saved none is not the same as no record.** Only a saved none stops
check-ins. An agent here may be Bestie in another community that shares
its instructions, so an account that never chose one leaves them alone.
The saved choice keeps this difference as `recorded()` next to
`snapshot()`. Rejected: a new record field, because the record is shared
with Solo and its reader rejects unknown keys.
- **The choice is known (`known()`) only after a successful read made
before any choice here, or after a successful save.** It is never known
while a save is pending. This gates both the cleanup and the Former tab.
Both are set by one `save()` wrapper around the account write, which
`chooseDefaultAgent` and main's `clearDefaultAgent` use.
- **One confirmation path for remote agents.** The empty-state chooser
and the Bestie actions render the same component and string, so the
warning can't drift. Rejected: two dialogs in a row when a remote agent
replaces a Bestie.
- **Switches off for remote agents.** A hosted agent's instructions live
with its provider, and an agent on another device keeps its timers
there, so a switch here would claim a change it can't make.

<details><summary>Reader diff</summary>

```diff
diff --git a/src/features/relay/native-sidebar.ts b/src/features/relay/native-sidebar.ts
index 9a2ae20..c771725 100644
--- a/src/features/relay/native-sidebar.ts
+++ b/src/features/relay/native-sidebar.ts
@@ -150,7 +150,12 @@ export function nativeSidebar(transport: ReadTransport) {
   ): Promise<T> {
     const current = await head(coordinate, signal);
     const draft = prepare(current.payload, current.createdAt);
-    if (same(current.payload, draft.next)) return draft.result;
+    // A saved main agent of none matches the empty value but is still a
+    // record, unlike none at all, so it is written even then.
+    const unchanged =
+      same(current.payload, draft.next) &&
+      (current.createdAt > 0 || coordinate !== "main-agent");
+    if (unchanged) return draft.result;
     // Reject unsupported/over-budget writes at the existing projection boundary.
     if (coordinate === "main-agent") mainAgent(draft.next);
     else project(coordinate, draft.next);
@@ -180,7 +185,10 @@ export function nativeSidebar(transport: ReadTransport) {
     decodeSidebarPreferences: decode,
     async readMainAgent(signal: AbortSignal) {
       const current = await head("main-agent", signal);
-      return current.createdAt ? mainAgent(current.payload) : undefined;
+      // A record of none reads as null, apart from no record at all.
+      return current.createdAt
+        ? (mainAgent(current.payload) ?? null)
+        : undefined;
     },
     async writeMainAgent(agent: string | null, signal: AbortSignal) {
       if (agent !== null && !agentKey.test(agent))
diff --git a/src/features/relay/transport.ts b/src/features/relay/transport.ts
index ff1b874..38fd1b8 100644
--- a/src/features/relay/transport.ts
+++ b/src/features/relay/transport.ts
@@ -165,8 +165,9 @@ export interface ReadTransport {
   readonly renameSidebarSection?: SidebarSectionRenameMutator;
   readonly writeSidebarStar?: SidebarStarMutator;
   /** Host-only private account record of the main agent the viewer chose:
-   * undefined when never saved or explicitly cleared. */
-  readMainAgent?(signal: AbortSignal): Promise<string | undefined>;
+   * null when they saved none or it was cleared, undefined when there is no
+   * record. */
+  readMainAgent?(signal: AbortSignal): Promise<string | null | undefined>;
   /** Null saves that this account has no main agent. */
   writeMainAgent?(agent: string | null, signal: AbortSignal): Promise<void>;
   /** Clears only the expected choice and returns the resulting choice. */
```
</details>

**Try it** (`just dev`, local agent Ada as Bestie with Remembers you and
Every hour on, and a hosted agent Sky if you have one)
1. In Ada's **Bestie** tab, click **Remove** under Remove as Bestie. The
dialog opens with focus on Cancel. Click **Remove as Bestie**.
2. Ada's Bestie tab is gone and a **Former Bestie** tab takes its place.
Remembers you is still on, Every hour is off, and the private channels
are unchanged.
3. Click **Make my Bestie again**. Ada is Bestie again, with no
confirmation, because there is no current Bestie to replace.
4. Open **Change** and pick Sky. One dialog asks to replace Ada and says
some bestie features aren't available with remote agents. Switch. Sky's
Bestie tab shows its switches as unavailable, and Ada's Every hour is
off.
5. Remove Sky, then in Agents choose **Make my bestie** on Sky. The
chooser's "Use Sky as your bestie?" dialog appears. Cancel leaves no
Bestie.
6. Failure path: go offline, then Remove. The dialog says the removal
couldn't be saved, and the Bestie stays.

**Known gaps**
- After Remove, the panel shows the agent's first tab rather than Former
Bestie.
- Another device keeps its old view of the Bestie until it next reads
the account, once per connection.
- With no Bestie, new chats in the composer fall back to an automatic
pick on this device. That pick isn't saved to the account.
- A remote agent made Bestie on another device of yours doesn't get
Remembers you turned on there either; it is turned on only for a local
agent, on the device that made it Bestie.

**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 (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](https://claude.com/claude-code)

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
arividar pushed a commit to minniai/minni-buzz-app that referenced this pull request Nov 4, 2026
## Why

The pinned Bestie DM from block#1935 needs a clear starting point when no
Bestie is saved. The old page instead launches a separate Builderlab
setup flow. This replaces that path with one chooser for existing agents
and new agents.

## What

- Explain what a bestie means, then offer a searchable picker with
avatars, names, and distinct identity labels.
- Open the picker below its field, capped at roughly four avatar rows,
with search above scrollable results.
- Reuse **Create agent**, save the choice to the account, and open the
canonical DM.
- Keep remote agents eligible, but ask before saving: “Some bestie
features aren’t available with remote agents.” Cancel leaves the choice
unchanged and keeps any newly created agent.
- Show the chooser in place when the saved agent is gone, and clear the
account choice after completed deletion.

## How

The chooser uses `session.agentChoices`, the shared creation dialog, the
existing `main-agent` record, and the pinned DM from block#1935. It adds no
messaging path or remote capability setup. The shared Combobox gains an
opt-in compact popup; other callers keep their current behavior.

Deletion checks the current account record before writing `agent: null`.
Native signing now admits that cleared value. Existing browser journeys
retain their plugin/default and navigation contracts with the new
heading; browser cases added/removed: **0/0**. The retired hosted-setup
UI assertions are replaced by mounted chooser/save/recovery coverage.

## Risk

This removes the separate Builderlab-specific Bestie onboarding, not
Builderlab agent creation. The remote warning does not turn on memory or
check-ins. Account cleanup is a read/replace, not an atomic
compare-and-swap: another device's choice in that gap can be
overwritten. A cleanup error reports that deletion completed but the
Bestie choice could not be cleared.

## Testing

Clay tried the running native app and iterated on the empty-state copy,
searchable picker, and popup size/placement. The remote confirmation was
opened through the production chooser in an isolated Chromium fixture
with a sample hosted agent; no real agent was created or account choice
saved.

Still deferred: live Builderlab creation → confirmation → account save →
DM; deletion and reload persistence on the rebased head; native
remote-warning focus behavior; and the full light/dark, viewport, and
enlarged-text acceptance pass. These checks remain outstanding; this PR
does not claim completed acceptance.

## Bigger picture

block#1935, Riley’s Bestie tab (block#2034), and its memory switch (block#2035) are
merged. This branch includes main through `23338bc84`, preserving both
alongside the empty-state chooser.

**Overlap with Riley's block#2047:** both replace the empty Bestie page and
clear a deleted choice. This PR contains the chooser UI Clay tested
today. Riley's PR sits above the Bestie settings/memory/check-in stack,
restricts Bestie to local agents, and wires selection into that setup.
This PR deliberately allows remote agents with a warning. The tab and
memory switch have landed independently. This chooser remains compatible
with both; later check-in and setup work must preserve the remote-agent
policy. That follow-up must reconcile the duplicate chooser/deletion
work and handle nonlocal capabilities without silently restoring a
local-only restriction. No changes to Riley's branches are included
here.

Generated with Goose

---------

Signed-off-by: Clay Delk <clay.delk@gmail.com>
Co-authored-by: Buzzsaw <a760f3ee1dc0daf403313e35766d0d983a8898aaa9ca95a034727165c63a8680@claysworld.communities.buzz.xyz>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Goose <goose@block.xyz>
arividar pushed a commit to minniai/minni-buzz-app that referenced this pull request Nov 4, 2026
The Bestie tab lists the private channels you share with Bestie. From
the tab you can add Bestie to one channel or to all your private
channels, and remove it from any of them.

**Why only private channels:** agents can already read public channels,
so only private channels need Bestie added.

**What changes**
- **Private channels Bestie can read:** each channel is listed with
**Remove**, which asks first, as the Members dialog does.
- **Add to a channel** (**Choose…**): a picker of your private channels
that don't have Bestie yet, most recently active first.
- **Add to all my private channels:** adds Bestie to every private
channel you're in that doesn't have it.
- Adds and removes are the same NIP-29 membership events the Members
dialog sends (kinds 9000/9001). After each one, the tab reads the roster
again to confirm. Remove and the config channels share one helper for
this, `administerMember` in `channel-members/administration.ts`.
- **Bestie joins as a guest**, so it reads the channel but can't post
there. `memberAdditions.add` takes an optional `{ role: "guest" }` for
this; every other addition keeps the role it had.
- **The browser host signs guest invitations**: its kind 9000 allowlist
now accepts `role=guest`, as well as no role or `role=member`. Owner,
admin and bot stay out of it.
- **An addition finishes only with the role it asked for** (shared with
the Members dialog and Outbox): an add already running, or a saved
receipt for the same channel and person, is reused only for the same
role. Otherwise the add stops with an error that says to retry or remove
the receipt in Outbox. No second write competes with it, and the receipt
stays. So a Members-dialog add no longer sends a new write past a saved
guest receipt, and Outbox **Retry** retries a guest addition as a guest.
- **Until the channel list has loaded in full**, the section says so
instead of saying Bestie is in none. A failed read shows **Retry**,
which reads the list again. The channels already known keep their rows,
and **Add to all** waits for the full list. A channel known only from a
cached list offers no Add or Remove until it is read again.
- **Keyboard focus stays in the section** when its control leaves: after
a Remove drops its row, or the last add takes **Choose…** and **Add to
all** with it, focus moves to the control now in its place, or to the
section heading. Focus you already moved elsewhere stays there.
- Each action has its own row, so in a narrow panel its button wraps
under the label.
- **Changing your Bestie stops an Add to all under way**, so the old
Bestie isn't added to the channels left.

**Try it** (`just dev`, with a local Bestie and two private channels it
isn't in)
1. Open the **Bestie** tab. Under **Private channels Bestie can read**,
click **Add to a channel → Choose…** and pick one channel. That channel
appears in the list, and its timeline shows that you added Bestie.
2. Click **Add to all**. The other channel is added too.
3. Click **Remove** on one channel and confirm. It leaves the list. With
the keyboard, focus moves to the next row.

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

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

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

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
arividar pushed a commit to minniai/minni-buzz-app that referenced this pull request Nov 4, 2026
The Bestie tab gets **Check-ins → Every hour**. Turned on, it wakes your
Bestie in your DM once an hour.

**Why a local timer:** a Bestie on this device is woken by a timer on
this device, using the same Attention timers as the Watching plugin.

**What changes**
- **Every hour** needs **Remembers you**. It is disabled while memory is
off, and turning memory off turns it off too.
- **On:**
- Adds an Hourly upkeep section (`buzz:bestie/checkin.hourly`) to the
instructions. Each check-in reads what's new in your DM and in the
private channels Bestie was added to, and reports only in the DM.
- Saves an hourly Attention timer, `watch/bestie-hourly-check-in`,
through `agents.save`; the timer wakes Bestie in your DM.
  - Turns on the agent's Attention.
- **Off** removes the section and the timer. It leaves Attention on,
because the agent's other watches may need it.
- The timer runs while Buzz is open and Watching is on. While it can't
run, the row says **Paused**. A timer paused in the Attention tab, which
can't resume it, says **Paused in Attention** and how to restart it;
**Off** still works. After a sleep it runs once, not once for each
missed hour.

**Design decisions**
- No `controlAttention()`. Turning Watching off still stops every
agent's Attention, so Bestie doesn't take over a control the user can
see. Rejected: having the plugin turn Attention on through
`controlAttention()`.
- The timer is saved first, then the instructions, so a failed save
leaves no section without a timer. If the instructions fail to save,
**On** undoes the timer, and turns Attention back off only if it turned
it on. If that undo fails too, a row says the timer is still saved and
offers **Remove**.

**Try it** (`just dev`, local Bestie with Remembers you on)
1. Turn **Every hour** on. The Watching tab shows the timer
`watch/bestie-hourly-check-in`, and Instructions has the Hourly upkeep
section.
2. Turn **Remembers you** off. **Every hour** turns off and is disabled.
3. Turn memory back on, then check-ins on, then disable the Watching
plugin. The row says it is paused.

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

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

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

buzz-review-completed

---------

Signed-off-by: Riley Crane <rileycrane@squareup.com>
Co-authored-by: eggboy <3986e5374b8c11a274f4a53fa9a68e1e18b53e712f8aa5218add2485bf5a2b09@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
arividar pushed a commit to minniai/minni-buzz-app that referenced this pull request Nov 4, 2026
…ie tab (block#2039)

When you change your Bestie, the old one stops checking in, and its
other settings stay where you can reach them in a **Former Bestie** tab.

**Why:** only one agent should check in on you. A former Bestie's other
settings (memory, channels) are still on, so they stay reachable in
their own tab instead of becoming invisible.

**What changes**
- **Only your Bestie checks in.** Whenever the saved Bestie is known,
every other local agent has its check-in section and timer removed. Its
memory section and channels stay. A choice made on another device counts
once this device next reads the account, once per connection.
- **Former Bestie tab:** it shows "<name> is no longer your Bestie.
These are still on.", the same switches, **Remove from all** for its
private channels, and **Make my Bestie again**. The tab shows while the
agent has a Bestie section or, if this device saw it as Bestie, while it
is in one of your private channels.
- **New Bestie starts remembering.** An agent this device makes Bestie
starts with Remembers you on (the plugin hears `onBestieMade`). A choice
synced from another device changes nothing, so memory turned off stays
off.
- **Tests:** a browser layout check (`tests/browser`) covers the Bestie
and Former Bestie tabs at two panel widths and two text sizes.

**Design decisions**
- Cleanup acts only on a Bestie the account has saved. While the account
is still being read, nothing is removed.
- Turning the Bestie plugin off stops a cleanup already under way: it
saves nothing more, not even the instructions after a timer save, and
starts no further pass.
- Former Bestie is a second tab (`buzz.bestie/former-bestie`), not a
mode of the Bestie tab, so each tab's `when` stays simple.

**Try it** (`just dev`, with two local agents, Ada as Bestie with
Remembers you and Every hour on)
1. In Ada's **Bestie** tab, **Change** to Bea and confirm.
2. Ada now has a **Former Bestie** tab: Remembers you is still on, Every
hour is off, and its timer is gone from Watching.
3. Bea has the **Bestie** tab, with Remembers you on.
4. In Ada's Former Bestie tab, click **Make my Bestie again** and
confirm. Ada has the Bestie tab again.

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

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

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

buzz-review-completed

---------

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

3 participants