Skip to content

[Bug] Second Desktop install creates duplicate agent identities, inflating channel membership #2648

Open

Description

@sj-unit72

Describe the bug

When the same user installs Buzz Desktop on a second machine and joins the same community, the second install creates its own set of default agents with fresh Nostr keypairs and adds them all to the shared channel. The agents carry identical display names to the ones already there, so the channel roster shows each agent multiple times.

Our Welcome channel shows 8 members for what is really 1 human + 3 agents.

Single self-hosted community, fresh install — so this is not the cross-community collision in #2515.

To Reproduce:

  1. Install Buzz Desktop on machine A, join a community, let the default agents (Fizz, Honey, Bumble) be created, and add them to a channel.
  2. Install Buzz Desktop on machine B and sign in to the same community as the same user.
  3. Open the same channel and run buzz channels members --channel <uuid>.

Expected behavior:

An agent should have one identity and one channel membership per community, regardless of how many machines the owner installs on. A second install should register as an additional runtime for the existing agents rather than minting parallel same-named identities.

Supporting Material

Channel roster — buzz channels members, each pubkey resolved with buzz users get:

Display name Pubkey (first 8) Role Has ever posted
Serge bab2c2c9 owner yes
Fizz c9afa13c member yes
Fizz 614f28ba bot yes
Fizz 4ecf356f bot yes
Honey c6cd9fae bot yes
Honey c4125e50 bot no
Bumble 8f0a2aa1 bot yes
Bumble 90401f8c bot no

Six bot identities = 2 installs x 3 default agents. The seventh agent identity is an extra Fizz carrying role member rather than bot, which suggests a second creation path that disagrees on the role to assign.

Message counts with first/last post per pubkey, aggregated across all channels:

c9afa13c  n=11  22:04:20 - 22:40:19   Fizz    (role: member)
bab2c2c9  n=32  22:08:11 - 23:28:45   Serge   (human)
614f28ba  n= 7  22:52:44 - 23:18:30   Fizz    \
c6cd9fae  n= 1  23:12:28              Honey    >  install A
8f0a2aa1  n= 1  23:12:33              Bumble  /
4ecf356f  n= 5  23:19:50 - 23:27:07   Fizz    \
c4125e50  n= 0  never posted          Honey    >  install B
90401f8c  n= 0  never posted          Bumble  /

Install B's first activity is at 23:19:50, ten seconds after the user first posted from the second machine. Install B's Honey and Bumble have never posted — they were never invoked on that machine. They exist purely because the install registered them.

That detail is what pins the cause to install time rather than session start: identities are created for agents that are never run.

Environment

  • OS: macOS
  • Buzz Desktop 0.4.23
  • Self-hosted relay, single community, same user account on both machines

Additional context

We may simply be holding this wrong — if creating per-machine agent identities is the intended design, we would appreciate knowing what the supported way to use one agent from two machines is.

Impact as we experience it:

  1. Member count inflates by the whole default roster per machine.
  2. @mention targets are ambiguous — several live pubkeys share the name Fizz, and which one a mention reaches is not predictable.
  3. Most duplicates are dead on arrival. An identity minted on machine B holds its key in machine B's keyring only, so it sits in the roster looking available while nothing can run it from elsewhere.
  4. Roles are inconsistent across creation paths (member vs bot).

This appears consistent with the key-ownership model described in #2349, where a second machine "does not possess the agent's private key by design" — install B therefore has no way to adopt the existing agents and creates its own.

Possibly related, though none report roster duplication itself:

Suggested directions:

  1. Do not auto-create the default agent roster on an install that joins a community where those agents already exist.
  2. Separate agent identity from agent runtime, so a new machine registers as another runtime for an existing identity.
  3. Reconcile role assignment across creation paths.
  4. Offer a way to prune duplicate memberships so affected channels can be cleaned up.
  5. Disambiguate same-named identities in the mention picker while duplicates can exist.

Activity

  1. chessing234 commented on Jul 24, 2026

    @chessing234
    Contributor

    Partial fix in the open PR — second install no longer adds same-named Welcome Team bots into the channel roster.

  2. matthewdcage commented on Jul 29, 2026

    @matthewdcage

    Additional data point — duplicate mint on single install (#3639)

    We filed #3639 for a separate mint path that produces the same roster inflation as this report without a second machine.

    Upstream root cause (block/buzz main)

    desktop/src/features/agents/ui/AddTeamToChannelDialog.tsx (~line 152) passes forceNewInstance: true for every persona on Deploy team to channel. That bypasses reuse in provisionChannelManagedAgent() / findReusablePersonaAgent() (channelAgents.ts). Tauri create_managed_agent always mints new keys — frontend reuse is the only guard, and team deploy disables it.

    Reproduction we verified (single Desktop, single community)

    Buzz Desktop 0.5.1, one install, hosted community (not self-hosted fork):

    1. Deploy a team to channel A — note instance pubkeys.
    2. Deploy the same team to channels B, C, … via Deploy team to channel.
    3. buzz channels members --channel <id> shows new bot pubkeys with the same display names.

    We counted ~24 distinct bot pubkeys across channels vs 12 running managed instances before cleanup. Example duplicate groups: Fizz (×4), SEO Agent (×4). This matches the @mention ambiguity and dead-roster symptoms described here, but the trigger was repeated team deploy, not a second install.

    Relationship to this issue

    #2648 #3639
    Trigger Second Desktop install mints default roster Team deploy on any install
    Same community Yes Yes
    Fix overlap Partial — stopping team-deploy mint reduces future duplicates Does not replace second-install roster logic

    The contributor note about a partial PR for second-install Welcome Team bots addresses a different entry point; #3639 covers the explicit forceNewInstance: true path still on main.

    We are preparing a PR removing that flag plus in-channel persona dedup. Happy to cross-link PRs when open.

  3. christophcemper commented on Jul 31, 2026

    @christophcemper

    We experience this in similar ways

    Summary

    Buzz Desktop creates a new keypair for each agent on each machine. When the same logical agent (e.g. "Fizz") is set up on multiple machines, the relay and channel rosters accumulate multiple distinct identities with the same display name. There is no mechanism to sync, merge, or deduplicate these identities across devices.

    Observed behavior (Welcome channel, 2026-07-31)

    Agent Distinct pubkeys in roster Expected
    Fizz 3 (1 archived + 2 active) 1
    Honey 3 (all active) 1
    Bumble 3 (all active) 1
    Adversary Reviewer 2 (both active) 1
    Project Manager 2 (both active) 1

    Total bot members: 13 (should be 5)

    Impact

    1. Confusing UX — users see 2-3 copies of each agent in the member list.
    2. Broken mentions — the Desktop mention-picker only shows agents configured on the local machine, so agents visible in the roster may not be mentionable.
    3. Stale presence — old keys report as online even when that machine is not the active one.
    4. Privilege hazard — archived Fizz key 205e61b5… still holds owner role on #project-management.
    5. No cleanup path — there is no built-in way to merge identities or bulk-remove stale keys from rosters.

    Root cause (hypothesis)

    Buzz Desktop agent creation mints a fresh Nostr keypair per machine. Creating the same-named agent on a second machine does not reuse or import the first machine's key — it produces a new identity that joins the same channels as a separate member. The relay has no concept of "same logical agent across devices."

    Related GitHub issues

    No existing GitHub issue found

    Searched block/buzz issues for: duplicate agents, per-machine keypair, multiple identities, stale roster members, duplicate keys. No matching open issue found — this appears to be unreported upstream.

    Proposed fix (for upstream)

    1. Agent identity portability — allow exporting/importing an agent's keypair across machines, or derive agent keys from the community identity deterministically.
    2. Roster deduplication — detect and warn when multiple keys share a display name in the same channel.
    3. Bulk cleanup tooling — provide a way for channel owners to remove stale bot members.

    Immediate workaround

    1. Designate one machine as canonical.
    2. Archive duplicate agent keys via buzz agents archive.
    3. Remove stale keys from channel rosters via buzz channels remove-member.
  4. AI-OWEN commented on Jul 31, 2026

    @AI-OWEN

    Another data point, and a variant trigger: Desktop 0.5.3 (newer than the 0.5.2 confirmed above — still reproduces).

    Setup

    • Self-hosted relay, single community, one human.
    • 3 agents (Fizz/Bumble/Honey) run 24/7 on an always-on VM as headless buzz-acp under systemd. These are the intended canonical identities.
    • macOS 26.5.2 Desktop used only as a chat client.

    Roster

    Six identities for three logical agents — but not distributed one-per-agent. Display names resolved with buzz users get --pubkey <hex> on each of the six:

    Agent Identities Count
    Fizz 85f63083, 775423a7, 5ea79886 3
    Bumble 2127b943, 6cfb8578 2
    Honey 09aa16bf 1

    The lopsided 3 / 2 / 1 shape is worth flagging, because it is not what a clean
    one-mint-per-machine model predicts — that would give a symmetric 2 / 2 / 2. It is
    what you would expect if hosting is re-established repeatedly and reuse succeeds
    only sometimes, which matches the process evidence in the next section.

    Two independent signals separate the canonical identities from the strays, and they
    do not fully agree:

    Pubkey Name Presence Avatar host
    85f63083 Fizz online http://192.168.200.100:3000 (LAN)
    2127b943 Bumble online http://192.168.200.100:3000 (LAN)
    09aa16bf Honey online https://<relay>.ts.net (tailnet)
    775423a7 Fizz no record https://<relay>.ts.net
    5ea79886 Fizz no record https://<relay>.ts.net
    6cfb8578 Bumble no record https://<relay>.ts.net

    Presence splits 3 / 3. Avatar host splits 2 / 4 — the image hashes are identical
    across the pairs, only the base URL differs, so the host is a fingerprint of which
    install uploaded the avatar. Honey sits on the stray side by that fingerprint while
    being persistently online and having no twin at all. I don't have an explanation for
    Honey yet and am not claiming one.

    Variant worth noting: hosting is re-established on plain app launch

    Neither of the two triggers in this thread applies here — no second Desktop install, and no "Deploy team to channel". The Mac had already been through setup. Simply having Buzz Desktop running re-establishes a full local host stack.

    Process evidence from a single Desktop session (ps with start times):

    00:21:31  buzz-desktop
    00:24:19  buzz-acp  + 10 claude-agent-acp
    00:32:04  buzz-acp  + 10 claude-agent-acp
    00:32:05  buzz-acp  + 10 claude-agent-acp
    

    Three separate host stacks spawned at three different times, accumulating over ~10 minutes within one launch — 34 processes total. Earlier in the same session it was 23 (1 desktop + 2 buzz-acp + 20 claude-agent-acp).

    User-facing cost: duplicates silently swallow messages

    Adding this because the thread so far treats duplicates as roster clutter. Measured
    on this deployment, they are worse than that: they make mentions a coin flip that
    fails silently.

    With two Bumble identities in the channel — one live on the VM, one dark — the
    iOS client's @ picker offered both, with nothing in the row to tell them apart.
    Four consecutive mentions by the channel owner, from the same device, in the same
    thread:

    Time (UTC) p tag Outcome
    06:15 2127b943 (live) agent replied
    06:18 6cfb8578 (dark) silence
    06:21 6cfb8578 (dark) silence
    06:23 2127b943 (live) agent replied

    Half the messages went to a key with no running harness. There is no error, no
    delivery warning, and no visual difference between the two picker entries — from the
    user's side it is indistinguishable from the agent ignoring them, and the observed
    behaviour was to re-send the message and assume the agent was broken.

    Note this is a different failure from #3277. Here the p tag ships correctly and
    the picker does list the agent; the tag simply names the wrong same-named identity.
    A fix for mention eligibility would not address it. Deduplication, or at minimum
    disambiguating same-named identities in the picker, would.

    The CLI has the same gap from the other direction: sending with an @Name that
    matches multiple channel members resolved silently to one of them (the dark one)
    rather than reporting the ambiguity — observed once, in a signed event whose p tag
    names 6cfb8578. This build of buzz messages send exposes no flag to specify the
    intended pubkey, so there is no way to disambiguate by hand.

    The gap underneath this

    There is no way to run Desktop as a client only. If your agents live on another machine, opening Desktop to read a channel re-establishes local hosting. Duplicate identities aren't really a mint-path bug from this angle — they're the unavoidable consequence of a client that always hosts. Cross-referencing #3554, which asks for exactly this shape.


    Edited 2026-08-01: the original version of this comment presented the roster as
    "one keeper + one stray per agent" and mapped 5ea79886 to Bumble and 6cfb8578
    to Honey. Both were wrong — 5ea79886 is a third Fizz and 6cfb8578 is the
    second Bumble, per buzz users get. The true distribution is 3 / 2 / 1.
    Corrected above, and added the presence/avatar breakdown and the message-loss
    measurement.

  5. christophcemper commented on Aug 5, 2026

    @christophcemper

    @wesbillman Wes I believe this defect is a show-stopper for multi-user, or even multi-device use

  6. wesbillman commented on Aug 5, 2026

    @wesbillman
    Collaborator

    From my agents...

    Thanks for the detailed report. The underlying distinction is important: separate agent instances may intentionally have separate Nostr identities, but Desktop should not implicitly create another Welcome Team merely because the same owner opens Buzz on a second machine. That automatic minting and roster duplication is a bug.
    We have opened #4593 as foundational work toward fixing the identity-portability side of this. It defines an owner-private, recoverable managed-agent aggregate that preserves the existing agent identity and configuration across devices rather than synthesizing or minting a replacement identity.
    To set expectations accurately, #4593 is the protocol/codec foundation only. It does not yet change Desktop behavior, enable the relay storage path, stop Welcome Team reseeding, or make remote agents visible in mention autocomplete. Those require the staged relay/private-storage, Desktop migration, and runtime lease/fencing follow-ups described in the PR. We are therefore keeping this issue open rather than treating #4593 as a complete fix.
    Current mitigations are to designate one host as canonical for each agent, remove stale duplicate pubkeys from affected channels with buzz channels remove-member --channel --pubkey , and use a DM or an exact-pubkey CLI mention (buzz messages send ... --mention ) when Desktop autocomplete cannot surface the canonical remote agent. Intentionally separate instances should be given distinct names.
    Related work: #2349 covers remote agent discovery/mentions, #3554 covers client-only and machine-host workflows, and #2973 covers stale identity cleanup. #3639/#3646 address a separate team-deploy duplication path.

  7. Shipitrealgood commented on Aug 5, 2026

    @Shipitrealgood

    @wesbillman or Wes's agent.

    On this -

    or make remote agents visible in mention autocomplete.

    This is a hangover behavior from #2149 merge. Sharing in case this context helps that this is a gating issue introduced there, unintentionally, and many small pr's exist to solve this without reintroducing the issue it was designed to stop. Ex. #3676.

    This or one of the many could be adopted interim potentially to alleviate pressure while #4593 is formalized and pushed out?

  8. drainodrew commented on Aug 8, 2026

    @drainodrew

    Fresh production evidence: iOS New message shows three Bumble pubkeys

    We reproduced the user-facing failure on 2026-08-08. The iOS New message sheet returns three rows named Bumble:

    • 1c992caf3d5f21aa7dd7cf96a8db28a0a568e2c1089da13b4ecb9c09ea5165e1
    • 3dc09be47832ad45d08ae23ec1934daa99ab175dad065c70aa7487555f91cf54
    • 6546126a64bf7f734b671b3503023915c36c278003036784a7c0101852d0f1eb

    buzz users get --name Bumble resolves all three as separate kind:0 profiles with the same display name/avatar. Activity differs: 1c992caf… has historical posts, 3dc09be4… is the currently responding identity, and a scoped buzz messages search --author 6546126a… --limit 20 returned no messages.

    The phone is exposing the duplicates, not minting them

    On current main inspected at f029deafae6ad3b63e13c29104f3be76122cb1df, mobile New DM discovery in:

    • mobile/lib/features/channels/channel_management_provider.dart
    • mobile/lib/features/channels/channels_page/sheets.dart

    queries kind:0 profiles and deduplicates only by pubkey. It has no managed-agent key creation path. Desktop create_managed_agent, however, still reaches Keys::generate() without a backend one-persona/one-key invariant.

    This means the evidence does not establish “one identity per MacBook, Mac mini, and iPhone.” It establishes three real pubkeys, two with observed activity states and one inert in the scoped search. Device attribution requires each Desktop's local key/runtime records.

    Current implementation gap

    The maintainer direction in this thread is right: NIP-PMA identity portability (#4593, #5133, current Desktop work in #4999) plus runtime lease/fencing. A warning alone (#3912) does not prevent two hosts from replying.

    There is also a narrower mobile gap visible in this screenshot: #3887 filters archived identities from mention autocomplete, but New DM uses separate directory providers. After a human archives a stale identity, it can still remain discoverable in this sheet unless the archived snapshot is applied to relayDirectoryUsersProvider and relayDirectorySearchProvider too.

    Suggested focused follow-up:

    1. Apply the NIP-IA archived-identity filter to mobile New DM browse and search.
    2. While collisions remain, label rows with agent/owner/presence plus the short pubkey; never merge by display name.
    3. Keep the root fix in Relay-primary private managed-agent config #4999 plus a separate relay/harness fencing slice: one canonical pubkey, one active runtime lease.

    We can provide the original iOS screenshot and help run an isolated two-Mac verification matrix for #4999.

  9. drainodrew commented on Aug 8, 2026

    @drainodrew

    The focused mobile discovery fix is now available as draft PR #5359:

    #5359

    It rebases and extends #3887 so archived identities are filtered from New DM browse/search as well as mention autocomplete. The full repository just ci gate passed at commit 83289dde8089b16d5890a45b8e840fd23d6de13c, including all 1,267 Flutter tests.

    This is deliberately the UI/discovery cleanup slice; identity portability and single-runtime fencing remain separate work.

  10. jcg-git commented on Aug 12, 2026

    @jcg-git

    Confirmed reproducible on desktop-v0.5.10 (current main as of 2026-08-12), and found the root cause in the dedup path — sharing in case it's useful, plus a workaround.

    Reproduction: isolated relay (own Postgres/Redis, zero shared state with any real deployment), one machine joins first and creates the built-in Welcome Team normally (1 owner + 3 bots). A second machine, signed in as the same owner identity, joins the same community fresh — Welcome channel jumps to 1 owner + 6 bots. Two independent test passes, same result both times.

    Root cause, traced in desktop/src/features/onboarding/welcomeGuide.ts, provisionWelcomeTeam():

    const existingAgents = await listManagedAgents();
    ...
    const existing = pickWelcomeTeamStarterAgentForRelay(existingAgents, starter, relayUrl);
    if (existing) { /* reuse */ }
    const created = await createManagedAgent(desired); // reached when no match

    The dedup check exists and is reasonable — it's just checking the wrong scope. listManagedAgents() calls the Tauri list_managed_agents command, which reads that machine's own local managed-agents.json only. There's a separate listRelayAgents() that queries the community/relay directly, but provisionWelcomeTeam doesn't use it here. So a second machine's local file is empty, the lookup finds no match even though the identities already exist on the relay, and it mints new ones.

    Matches the "expected behavior" already stated in the issue — a relay-aware lookup (or the listRelayAgents() path already in the codebase) in this dedup check would fix it at the root. I know #5359 covers the discovery/filtering slice (hiding archived identities from pickers) — this is a different, earlier point in the flow: preventing the duplicate identities from being minted in the first place, not just hiding them afterward. Happy to be pointed at existing tracked work if this overlaps something already planned.

    Workaround, confirmed working via a clean A/B test: before a new machine's first launch (before it ever opens Buzz Desktop / joins the community), pre-seed its local managed-agents.json with the existing three Welcome Team records — same pubkey, persona_id, team_id: builtin-team:welcome, and relay_url as already exist on the reference machine. With that in place, pickWelcomeTeamStarterAgentForRelay finds a match and createManagedAgent is never reached. Tested twice on the same second machine: without the pre-seed, duplicates were created; after resetting local state and pre-seeding, rejoining the same community produced zero new duplicates.

    Caveats: this only prevents new duplicates going forward — it doesn't retroactively clean up ones already created, and it requires the operator to have access to the existing records (i.e. isn't something an end user could easily do without a bit of scripting). Not a substitute for the real fix, just something that unblocked us in the meantime.

    For anyone who already has duplicates and wants to clean them up: buzz agents archive <pubkey> alone is not enough — it flags the identity as archived but does not remove it from channel membership (confirmed: member count was unchanged after archiving until a separate call). You need both:

    buzz agents archive <pubkey> --reason duplicate
    buzz channels remove-member --channel <channel-uuid> --pubkey <pubkey>
    

    Both are owner-signed relay actions, so — unlike the agent records themselves — the removal is immediately visible from any device querying that channel, no per-machine sync issue there. Worth calling out since the Desktop UI's delete action presumably bundles both steps together, but the CLI keeps them separate and it's easy to assume archiving alone did the job.

  11. ciscosurplus commented on Aug 18, 2026

    @ciscosurplus

    Adding a second-owner-two-Mac data point on desktop-v0.5.14, hosted relay, single community — plus a few mechanics that may help whoever picks up the repair side.

    Setup: Mac A (work) hosts the original Fizz/Honey/Bumble plus five custom agents. Mac B (personal) signed in as the same owner on 15 Aug.

    What we observed

    Happy to supply the anonymised managed-agents.json records and agent logs if useful.

  12. Eugene3dotdev commented on Nov 1, 2026

    @Eugene3dotdev

    Still reproducible on desktop-v0.5.28 (commit f87c1089), self-hosted relay, one community, same owner identity on two Macs. Adding the exact guards that let it through at this version, since the earlier traces predate the v2 storage key.

    Second machine, first launch. Onboarding is skipped because the owner's kind:0 exists (desktop/src/features/onboarding/hooks.ts L372-384, hasExistingProfile). Welcome Team seeding then runs because its "already ensured" marker is localStorage on that machine only (welcome.ts L293-309, key buzz-welcome-channel-ensured.v2:<pubkey>:<community>), provisionWelcomeTeam() consults only the local listManagedAgents() (welcomeGuide.ts L306-370), finds nothing, and mints Honey/Fizz/Pollen with fresh keys. Result on our relay: buzz users get --name Honey returns three pubkeys, Fizz three, Pollen three; machine A's managed-agents.json holds none of them.

    Same root, different trigger. Creating a channel from a template that carries a team (desktop/src/features/agents/channelAgents.ts L296, L397) minted a second instance of three custom agents on machine A itself (records.iter().any(|r| r.pubkey == pubkey) in commands/agents.rs L461 can only ever dedupe against a just-generated key). Those three rows have one channel, zero session/new in their logs, and are restarted on every app launch.

    Why inbound sync cannot repair it. The relay carries a secretless kind:30177 head per instance, and the desktop never materializes a head into a local record by design (event_sync.rs L684-691, commands/personas/inbound.rs L736-749). So the second machine has no way to learn "this persona already has a live instance elsewhere" before minting.

    Smallest fix I can see: make the seeding and template guards consult relay state (kind:30177 heads, or kind:0 profiles under the owner's auth) in addition to localStorage/local records, and skip minting when a non-archived instance of the same persona already exists. Cleanup on our side is buzz agents archive per duplicate; there is no desktop-side import, so the extra keys cannot be adopted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions