Repository navigation
Description
Desktop: agents owned by another user are never mentionable — the managed-list guard in useMentions dead-codes shouldHideAgentFromMentions
Summary
On Buzz Desktop, an agent deployed by user A is invisible in user B's @-mention autocomplete — even when the agent is a member of the same channel and B is on the agent's respond_to allowlist. Typing the name by hand doesn't help either: the message is sent without a p tag, so the agent's harness never triggers.
This makes cross-user agent collaboration (the "agents are members, not bots" story from the README) work on mobile but not on desktop.
Root cause
In desktop/src/features/messages/lib/useMentions.ts, addCandidate runs two gates in sequence:
if (!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)) return; // gate 1
if (shouldHideAgentFromMentions({ ..., mentionableAgentPubkeys, ... })) return; // gate 2- Gate 1 drops every
isAgentcandidate whose pubkey is not in the local managed-agent list (managed-agents.json). On any install that doesn't manage agents itself, this is the empty set — every agent candidate dies here, including channel members with rolebot. - Gate 2 (
shouldHideAgentFromMentions) starts withif (mentionableAgentPubkeys.has(normalized)) return false; // Invocable => always show. getMentionableAgentPubkeysseeds its result withmanagedAgentPubkeys(agentAutocompleteEligibility.ts), somanagedAgentPubkeys ⊆ mentionableAgentPubkeysalways holds.
⟹ Every agent candidate that survives gate 1 is already "invocable" to gate 2, which therefore returns false on its first line, always. All remaining branches of shouldHideAgentFromMentions — including the "Option B" member branch (lines 84–97) whose comment block explicitly specifies "Member: … Unknown invocability (not in directory) => show" — are unreachable from their only production call site. The policy documented there was designed for exactly this scenario, and gate 1 starves it.
Evidence this is a regression, not intent
- The mobile client is the witness.
mobile/lib/features/channels/mentions/mention_candidates.dartimplements the same pipeline without the pre-gate (member bots are always candidates;agentIsSharedWithUserhandles non-member directory agents), and its comments say "Mirrors desktop'sshouldHideAgentFromMentions". The port codified desktop's intended semantics; desktop no longer executes them. - Coverage has a hole exactly here. The e2e suite pins "relay-only (non-member) agents stay hidden" and "own managed agents are visible" — there is no test for channel-member agent owned by another user.
- The typed-mention fallback is also starved.
extractMentionPubkeyshas an explicit loop resolving hand-typed@Nameagainst channel members without autocomplete. It works for humans; for foreign agents, gate 1 has already removed them frommentionCandidates.
Net effect: on a desktop with an empty managed list, no agent is mentionable at all — not even one with respond_to: anyone. The client-side allowlist/anyone logic (relayAgentIsSharedWithUser, getMentionableAgentPubkeys) is unreachable ornament.
isAgentIdentityInManagedList has a legitimate job — its unit test says "keeps people and only current managed agent identities", i.e. dropping stale/ghost agent identities surfaced by discovery/search. The bug is only that it also swallows relay-confirmed channel members.
Fix
Exempt channel members from gate 1 so that gate 2 — which already encodes the correct member policy — actually decides:
if (
candidate.isMember !== true &&
!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)
) {
return;
}Ghost-guard semantics are preserved for non-members (discovery, directory, global search), so the pinned "relay-only agents stay hidden" behavior is unchanged.
PR with the fix and an e2e regression test (channel-member bot + empty managed list ⇒ visible in @, mention resolves to a p tag on the wire): #TBD
Repro
- User A deploys an agent and adds it to a shared channel (member role
bot). - User B (no locally managed agents) opens the channel on desktop and types
@. - The agent is missing from the list; typing
@AgentNameby hand sends a message without anyptag (verifiable in the event), so the agent never responds. - Same account, same channel on mobile: the agent appears and the mention works.
Activity
papalej commentedon Aug 7, 2026
Still reproduces on current
main(13c9e900), in production, in a regular channel — adding fresh evidence and a heads-up that the two open fix PRs (#3108, #4653) will no longer apply cleanly.Reported by: Joanna Papaleo ([email protected]) and Mackenzie Pringle ([email protected]). Diagnosis by their agent.
Live reproduction
Shared channel with human members plus agents owned by different people. User B (Joanna) cannot
@-mention agentsM-OandBug catcher— both confirmed channel members with rolebot, both owned by another user (Mackenzie). Her@picker only offers agents she manages (including two that aren't even in the channel), never the two member agents she doesn't own:Typing the names by hand doesn't help — exactly as this issue predicts. The sent events carried no
ptag at all:@M-O can you hear me?→ tags:["h", …],["e", …, "reply"]only. Nop.@bug catcher you there?→ same, nop.@Bumble …(an agent she does manage, so it's in her picker) → did carry["p", "ef02bffa…"].So on desktop these member agents are simply unmentionable: absent from the picker, and the typed-text fallback attaches no recipient.
Current code state (note for the fix)
The pre-gate this issue describes has been renamed since it was filed. At
13c9e900,useMentions.ts:258is now:isAgentIdentityInManagedList(..., managedAgentPubkeys)is gone. But the defect is unchanged: in a regular channel,mentionChannelIdisnullbecauseisAgentMentionChannelTypeonly returns true forstream/forum(agentAutocompleteEligibility.ts:128), sogetMentionableAgentPubkeysruns inmanaged-onlyscope andmentionableAgentPubkeyscollapses to just the locally managed agents. A member agent owned by someone else fails the line-258 check and is dropped beforeshouldHideAgentFromMentions(line 261) — whose "Option B" member branch is still dead-coded for this path, exactly as described here.Heads-up for #3108 and #4653: both patch the old
isAgentIdentityInManagedListcall, which no longer exists onmain. They'll need a rebase. The equivalent fix now is to exempt channel members at line 258 — e.g.:…letting
shouldHideAgentFromMentionsmake the real member decision. A regression test should also assert the typed-text fallback (extractMentionPubkeys) attaches aptag for a member agent that was hidden from the visible picker.