Describe the bug
An agent owned by one person can never appear in another person's @ mention autocomplete, in any channel, under any configuration. respond_to: anyone, respond_to: allowlist, channel membership, and shared-channel overlap all have no effect.
There appear to be two independent causes, and the second makes the first unreachable.
Cause 1 — the eligibility gate is unreachable for agents you don't own
useMentions.ts applies three gates in order (v0.5.1 desktop/src/features/agents/hooks/useMentions.ts:245-262):
if (isArchivedDiscovery(pubkey)) return;
if (!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)) return; // :249
if (shouldHideAgentFromMentions({…})) return; // :252
isAgentIdentityInManagedList (lib/agentAutocompleteEligibility.ts:57-65) keeps a candidate only if isAgent !== true or its pubkey is in managedAgentPubkeys. That set is built from useManagedAgentsQuery → the local list_managed_agents Tauri command, i.e. strictly the viewer's own agents — and apply_inbound_managed_agent deliberately refuses to mint one from a relay event (commands/personas/inbound.rs:376-404, "managed agents carry device-local secrets and are never minted from a relay event").
Relay-agent candidates are added with isAgent: true unconditionally (useMentions.ts:334-346), and member candidates get isAgent: true whenever profile?.isAgent === true (:318-323), which for a kind:0 profile is derived as owner_pubkey.is_some() (nostr_convert.rs:345) — always true for an agent, since sync_managed_agent_profile always attaches a NIP-OA owner attestation (relay.rs:401-455).
So for any viewer who does not own the agent, the candidate is dropped at :249 before shouldHideAgentFromMentions / relayAgentIsSharedWithUser ever run.
Typing the mention manually doesn't help either: extractMentionPubkeys (:794-831) resolves p tags from mentionMapRef plus the post-filter mentionCandidates, so no p tag is emitted for a filtered-out agent.
Cause 2 — relayAgentIsSharedWithUser reads an event kind nothing publishes
Even if Cause 1 is fixed, the eligibility logic is inert. relayAgentIsSharedWithUser (lib/agentAutocompleteEligibility.ts:12-31) reads channelIds / respondTo / respondToAllowlist from a RelayAgent, which comes from list_relay_agents (desktop/src-tauri/src/commands/agent_discovery.rs:1057-1074) — a query for exactly [{"kinds":[10100]}].
Nothing in the repo publishes a kind:10100 agent profile. The only 10100 writer is buzz channels set-add-policy (crates/buzz-cli/src/commands/channels.rs:1004-1038), whose content is {"channel_add_policy": …}. Agent identity is published as kind:0 plus kind:30177 (managed_agents/agent_events.rs), and the persona catalog as kind:30175. The eligibility path never consults 30177.
Consequently agents_from_events (nostr_convert.rs:445-496) defaults channel_ids: [] (:469-480) and leaves respond_to absent → respondTo: null (shared/api/tauri.ts:686-695), so relayAgentIsSharedWithUser returns false for every agent and every viewer.
Secondary effect: publishing a 10100 makes things worse. directoryAgentPubkeys is every pubkey in relayAgentsQuery.data, with no eligibility filter (useMentions.ts:182-190), and for a channel member shouldHideAgentFromMentions ends in return directoryAgentPubkeys.has(normalized) (agentAutocompleteEligibility.ts:85-97). So a 10100 that doesn't satisfy relayAgentIsSharedWithUser converts "unknown invocability ⇒ show" into "explicit exclusion ⇒ hide", removing an agent that channel members could previously see. Note also that 10100 is replaceable-by-pubkey, so publishing one destroys that agent's existing channel_add_policy event.
Steps to reproduce
- User A creates an agent, sets Responds to: Anyone, and adds it as a member of a channel shared with user B.
- Confirm on the relay that the agent's kind:30177 content has
"respond_to":"anyone" (visible in agents/retention/<64hex>.db, table persona_events).
- As user B, in that shared channel, type
@ followed by the agent's exact name.
- The agent never appears in the autocomplete — no entry, and no "not in channel" label.
Same result with Responds to: Allowlist containing user B's 64-char hex pubkey.
Expected behavior
An agent whose owner has set respond_to: anyone (or an allowlist including the viewer) and which shares a channel with the viewer should be selectable in that viewer's mention autocomplete — which is what relayAgentIsSharedWithUser and the respond_to setting both clearly intend.
Version and platform
- Buzz version: 0.5.1 (verified unchanged in 0.5.2 —
agentAutocompleteEligibility.ts, agent_discovery.rs, agent_events.rs are all identical between the two tags)
- OS: macOS 15 (Darwin 25.4.0), Apple Silicon
Logs / additional context
The agent-side gate is configured correctly and is not the problem: record.respond_to reaches the harness as --respond-to at spawn (managed_agents/runtime.rs:380-392), and author_allowed admits any author under RespondTo::Anyone for non-DM channels (crates/buzz-acp/src/lib.rs:250). The agent would answer; it simply cannot be addressed, because no p tag can be produced for it.
Possible fix directions (happy to open a PR if you can indicate a preference):
- Cause 1 — allow a candidate through
:249 when its pubkey is in relayAgentsQuery and it passes relayAgentIsSharedWithUser, rather than requiring local ownership; and relax the corresponding early-return in extractMentionPubkeys so the p tag is emitted.
- Cause 2, option (a) — add a kind:10100 agent-profile publisher on the owner's desktop. Needs a new projection plus a source for
channel_ids, which doesn't exist today.
- Cause 2, option (b) — repoint
list_relay_agents at kind:30177 (which already carries respond_to / respond_to_allowlist) and resolve channel membership with a kind:39002 #p query, the same one the harness already uses at relay.rs:651-668. This needs no relay change and seems the cleaner shape.
Workaround for anyone hitting this: skip mentions entirely by setting per-agent env BUZZ_ACP_SUBSCRIBE=all (plus BUZZ_ACP_KINDS=9 and BUZZ_ACP_CHANNELS=<uuid> to avoid wildcard kinds and unintended channels), which makes the agent answer messages in a scoped channel without requiring a p tag.
Describe the bug
An agent owned by one person can never appear in another person's
@mention autocomplete, in any channel, under any configuration.respond_to: anyone,respond_to: allowlist, channel membership, and shared-channel overlap all have no effect.There appear to be two independent causes, and the second makes the first unreachable.
Cause 1 — the eligibility gate is unreachable for agents you don't own
useMentions.tsapplies three gates in order (v0.5.1desktop/src/features/agents/hooks/useMentions.ts:245-262):isAgentIdentityInManagedList(lib/agentAutocompleteEligibility.ts:57-65) keeps a candidate only ifisAgent !== trueor its pubkey is inmanagedAgentPubkeys. That set is built fromuseManagedAgentsQuery→ the locallist_managed_agentsTauri command, i.e. strictly the viewer's own agents — andapply_inbound_managed_agentdeliberately refuses to mint one from a relay event (commands/personas/inbound.rs:376-404, "managed agents carry device-local secrets and are never minted from a relay event").Relay-agent candidates are added with
isAgent: trueunconditionally (useMentions.ts:334-346), and member candidates getisAgent: truewheneverprofile?.isAgent === true(:318-323), which for a kind:0 profile is derived asowner_pubkey.is_some()(nostr_convert.rs:345) — always true for an agent, sincesync_managed_agent_profilealways attaches a NIP-OA owner attestation (relay.rs:401-455).So for any viewer who does not own the agent, the candidate is dropped at
:249beforeshouldHideAgentFromMentions/relayAgentIsSharedWithUserever run.Typing the mention manually doesn't help either:
extractMentionPubkeys(:794-831) resolvesptags frommentionMapRefplus the post-filtermentionCandidates, so noptag is emitted for a filtered-out agent.Cause 2 —
relayAgentIsSharedWithUserreads an event kind nothing publishesEven if Cause 1 is fixed, the eligibility logic is inert.
relayAgentIsSharedWithUser(lib/agentAutocompleteEligibility.ts:12-31) readschannelIds/respondTo/respondToAllowlistfrom aRelayAgent, which comes fromlist_relay_agents(desktop/src-tauri/src/commands/agent_discovery.rs:1057-1074) — a query for exactly[{"kinds":[10100]}].Nothing in the repo publishes a kind:10100 agent profile. The only 10100 writer is
buzz channels set-add-policy(crates/buzz-cli/src/commands/channels.rs:1004-1038), whose content is{"channel_add_policy": …}. Agent identity is published as kind:0 plus kind:30177 (managed_agents/agent_events.rs), and the persona catalog as kind:30175. The eligibility path never consults 30177.Consequently
agents_from_events(nostr_convert.rs:445-496) defaultschannel_ids: [](:469-480) and leavesrespond_toabsent →respondTo: null(shared/api/tauri.ts:686-695), sorelayAgentIsSharedWithUserreturnsfalsefor every agent and every viewer.Secondary effect: publishing a 10100 makes things worse.
directoryAgentPubkeysis every pubkey inrelayAgentsQuery.data, with no eligibility filter (useMentions.ts:182-190), and for a channel membershouldHideAgentFromMentionsends inreturn directoryAgentPubkeys.has(normalized)(agentAutocompleteEligibility.ts:85-97). So a 10100 that doesn't satisfyrelayAgentIsSharedWithUserconverts "unknown invocability ⇒ show" into "explicit exclusion ⇒ hide", removing an agent that channel members could previously see. Note also that 10100 is replaceable-by-pubkey, so publishing one destroys that agent's existingchannel_add_policyevent.Steps to reproduce
"respond_to":"anyone"(visible inagents/retention/<64hex>.db, tablepersona_events).@followed by the agent's exact name.Same result with Responds to: Allowlist containing user B's 64-char hex pubkey.
Expected behavior
An agent whose owner has set
respond_to: anyone(or an allowlist including the viewer) and which shares a channel with the viewer should be selectable in that viewer's mention autocomplete — which is whatrelayAgentIsSharedWithUserand therespond_tosetting both clearly intend.Version and platform
agentAutocompleteEligibility.ts,agent_discovery.rs,agent_events.rsare all identical between the two tags)Logs / additional context
The agent-side gate is configured correctly and is not the problem:
record.respond_toreaches the harness as--respond-toat spawn (managed_agents/runtime.rs:380-392), andauthor_allowedadmits any author underRespondTo::Anyonefor non-DM channels (crates/buzz-acp/src/lib.rs:250). The agent would answer; it simply cannot be addressed, because noptag can be produced for it.Possible fix directions (happy to open a PR if you can indicate a preference):
:249when its pubkey is inrelayAgentsQueryand it passesrelayAgentIsSharedWithUser, rather than requiring local ownership; and relax the corresponding early-return inextractMentionPubkeysso theptag is emitted.channel_ids, which doesn't exist today.list_relay_agentsat kind:30177 (which already carriesrespond_to/respond_to_allowlist) and resolve channel membership with a kind:39002#pquery, the same one the harness already uses atrelay.rs:651-668. This needs no relay change and seems the cleaner shape.Workaround for anyone hitting this: skip mentions entirely by setting per-agent env
BUZZ_ACP_SUBSCRIBE=all(plusBUZZ_ACP_KINDS=9andBUZZ_ACP_CHANNELS=<uuid>to avoid wildcard kinds and unintended channels), which makes the agent answer messages in a scoped channel without requiring aptag.