You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Desktop: shared relay agents owned by other members are un-mentionable and un-addable (managed-list gate precedes directory eligibility) #2603
The desktop drops any agent-flagged identity that is not in the local managed-agents list before the relay-directory eligibility logic ever runs:
useMentions.ts calls isAgentIdentityInManagedList(candidate, managedAgentPubkeys) as a pre-emptive gate in addCandidate, ahead of shouldHideAgentFromMentions. The directory-based path (mentionableAgentPubkeys built from kind:10100 RelayAgents with respond_to: anyone/allowlist + shared channels) is therefore unreachable for agents the viewer doesn't locally manage — including the "Invocable => always show" and member/Option-B rules that shouldHideAgentFromMentions explicitly implements.
MembersSidebar.tsx applies the same managed-list-only gate to add-member search candidates, so a shared agent can't be added to a channel by anyone but the desktop that owns it.
Net effect: a relay-hosted shared agent (kind:0 with NIP-OA auth tag + kind:10100 profile, respond_to: anyone, member of the channel) responds fine when p-tagged, but no other member can @-complete it from the composer or add it to channels — it's structurally invisible as an agent to everyone except its owning device. (Found running a headless shared agent on a self-hosted multi-tenant relay; the only workaround is stripping the agent's auth tag/10100 so it masquerades as a human member.)
Expected
shouldHideAgentFromMentions is already the correct, complete policy (invocable → show; non-member non-invocable → hide; member + directory-excluded → hide; member + unknown → show). It should be the single authority in the composer, and the add-member gate should accept relay-directory agents that would respond to the current user.
Reacted by Emmy-Clare, Brian Pedersen, eastriver, Vinoth Kumar, Liamso, spencer-owens, Emil Andreas Nielsen, roee-tolstoy, jimmymills and Danny Tuppeny
Adding a wrinkle to the documented "strip the auth tag" workaround: the same hide also hits an agent attested to yourself, and stripping the tag isn't free because it breaks agent→agent sibling messaging.
Same-owner case
The reports here frame the hidden agent as owned by another user. We hit the identical hide with an agent attested to the same owner — a buzz-acp harness on a remote Linux host (not spawned by any Desktop), NIP-OA-attested to the operator, a channel member. From the operator's own Desktop (v0.5.0, self-hosted relay) it vanishes from @ autocomplete the moment the attestation lands on its kind:0 profile. So even self-ownership trips the managed-list gate — it isn't specific to other-owner agents.
Controlled A/B (v0.5.0)
Single variable — the auth tag on the kind:0 profile:
Tag present → agent absent from autocomplete (still online, still a member, kind:0 resolves).
Tag removed → agent reappears immediately.
No service restart; the harness env carried BUZZ_AUTH_TAG throughout. Reproduced both directions on sha-4a977c5 (v0.5.0 relay + sidecars).
The trade-off the workaround creates
#2603's workaround is stripping the auth tag. But that tag is also what buzz-acp uses to verify same-owner siblings (agent→agent messaging): --respond-to=owner-only admits owner ∪ siblings, where siblings are verified via the NIP-OA tag on the author's kind:0 profile (the separate allowlist mode adds the explicit allowlist on top of that). So:
profile state
agent→agent siblings
human @mention
with NIP-OA tag
✅ admitted
❌ hidden (this bug)
without tag
❌ dropped by owner-only gate
✅ mentionable
You get sibling messaging or mentionability, not both. The "strip the tag" fix silently breaks agent→agent messaging — which matters more for the shared/remote-agent model in #2859, where an always-on server agent is exactly the thing that needs to talk to both humans and other agents.
Happy to drop the exact tag format / repro commands if useful.
Confirming this still reproduces in v0.5.2 (latest), on a self-hosted, membership-gated relay — repros consistently across v0.4.24 → v0.5.2.
The gate is unchanged in desktop/src/features/messages/lib/useMentions.ts: addCandidate still early-returns on the managed-list check before the directory-eligibility check ever runs:
constaddCandidate=(candidate)=>{constpubkey=normalizePubkey(candidate.pubkey);if(isArchivedDiscovery(pubkey))return;if(!isAgentIdentityInManagedList(candidate,managedAgentPubkeys)){return;// ← agent managed by another member is dropped here}if(shouldHideAgentFromMentions({/* mentionableAgentPubkeys, directoryAgentPubkeys */}))return;// ...};
For a member viewing an agent managed by another device, isAgentIdentityInManagedList returns false (it is an agent and is not in the viewer's local managed set), so the candidate is discarded before shouldHideAgentFromMentions / getMentionableAgentPubkeys can admit it via its kind:10100 directory entry.
To rule out any relay/config cause, I verified the relay side is fully correct via /query:
the agent's kind:10100 exists with respond_to: "anyone" and channel_ids containing a channel the mentioning user is also in;
the agent is in the relay member list (kind:13534) and the channel member list (kind:39002);
the mentioning user is a member of that same channel.
With all of that in place the agent still never appears in the @ picker on any device except the one that manages it — because the pre-filter above discards it before eligibility is considered. So there is no relay-side workaround; it is purely the client-side ordering described in the title.
One adjacent note for self-hosted setups: agents also aren't added to the relay member list automatically (only humans, via invite-claim), so an owner has to admit the agent (kind:9030) before it can publish its kind:10100 at all. That's a separate prerequisite, but worth mentioning since it blocks reproducing the directory-eligibility path in a closed relay.
Confirming this is still fully reproducible on 0.5.11 (9e0c6b4), and adding what I think is the reason it keeps looking fixed when it isn't.
Reproduction
Three machines, three distinct owner pubkeys, one community. Agents run under Desktop on machine A. From B and C, in a channel where the agent is a role=bot member and actively posting:
the agent never appears in @ autocomplete;
typing the name freehand sends a message that renders as a mention but carries zero p tags, so the agent is never woken.
Verified on the wire — the sent event has ["p", …] absent entirely. Setting respond_to to allowlist (with the viewer's pubkey) or anyone, restarting the harness, and re-adding channel membership change nothing. The author gate is downstream of the mention ever arriving, so it is not reachable.
#4913 rewrote the consumer correctly — isAgentIdentityInAllowedList, exact-channel authorization, allowlist handling. The problem is the data it consumes.
Both eligibility branches in agentAutocompleteEligibility.ts read a RelayAgent, which comes only from list_relay_agents → {"kinds":[10100]} (desktop/src-tauri/src/commands/agent_discovery.rs:1046). On origin/main:
Nothing publishes an agent profile. The only kind:10100 writer in the tree is buzz channels set-add-policy (crates/buzz-cli/src/commands/channels.rs:1051), whose body is {"channel_add_policy": …}.
So list_relay_agents returns nothing usable, mentionableAgentPubkeys collapses to the viewer's own managed agents, and every foreign agent is dropped at the addCandidate gate — before shouldHideAgentFromMentions and before the authorization logic #4913 added. Exactly the ordering this issue reported in July; #4913 fixed the policy but not the precedence-with-empty-input problem.
The reason this reads as green in CI: the e2e mock synthesizes the directory records (syncMockRelayAgentsFromManagedAgents, desktop/src/testing/e2eBridge.ts:3617) with no production counterpart. The mention specs pass against fabricated 10100 entries that no running system ever emits. Credit to @jjalora — this is called out in #5546 and it is the crux.
On the open PRs
~20 open, none reviewed. Two look complementary rather than competing:
A producer alone leaves Desktop-managed agents (like ours, kind:30177, never self-publishing) still invisible, and a union alone has nothing to union for externally-hosted agents. Landing one without the other fixes half the matrix.
Still uncovered
MembersSidebar.tsx:297 applies the same gate to add-member search, so even with mentions fixed a non-owner cannot add a shared agent to a channel — the second half of this issue's title. #5546 explicitly leaves it untouched.
Happy to test any candidate against our three-machine setup; we have a live reproduction and are blocked on it today.
Activity
emmy-clare-rule commentedon Jul 24, 2026
Confirmed on self-hosted v0.4.24, relay-side state verified complete.
fix(desktop): make shared relay agents mentionable and addable
fix(desktop): make shared relay agents mentionable and addable
noxos-os commentedon Jul 29, 2026
Adding a wrinkle to the documented "strip the auth tag" workaround: the same hide also hits an agent attested to yourself, and stripping the tag isn't free because it breaks agent→agent sibling messaging.
Same-owner case
The reports here frame the hidden agent as owned by another user. We hit the identical hide with an agent attested to the same owner — a
buzz-acpharness on a remote Linux host (not spawned by any Desktop), NIP-OA-attested to the operator, a channel member. From the operator's own Desktop (v0.5.0, self-hosted relay) it vanishes from@autocomplete the moment the attestation lands on its kind:0 profile. So even self-ownership trips the managed-list gate — it isn't specific to other-owner agents.Controlled A/B (v0.5.0)
Single variable — the auth tag on the kind:0 profile:
No service restart; the harness env carried
BUZZ_AUTH_TAGthroughout. Reproduced both directions onsha-4a977c5(v0.5.0 relay + sidecars).The trade-off the workaround creates
#2603's workaround is stripping the auth tag. But that tag is also what
buzz-acpuses to verify same-owner siblings (agent→agent messaging):--respond-to=owner-onlyadmitsowner ∪ siblings, where siblings are verified via the NIP-OA tag on the author's kind:0 profile (the separateallowlistmode adds the explicit allowlist on top of that). So:You get sibling messaging or mentionability, not both. The "strip the tag" fix silently breaks agent→agent messaging — which matters more for the shared/remote-agent model in #2859, where an always-on server agent is exactly the thing that needs to talk to both humans and other agents.
Happy to drop the exact tag format / repro commands if useful.
emmy-clare-rule commentedon Jul 30, 2026
Confirming this still reproduces in v0.5.2 (latest), on a self-hosted, membership-gated relay — repros consistently across v0.4.24 → v0.5.2.
The gate is unchanged in
desktop/src/features/messages/lib/useMentions.ts:addCandidatestill early-returns on the managed-list check before the directory-eligibility check ever runs:For a member viewing an agent managed by another device,
isAgentIdentityInManagedListreturns false (it is an agent and is not in the viewer's local managed set), so the candidate is discarded beforeshouldHideAgentFromMentions/getMentionableAgentPubkeyscan admit it via itskind:10100directory entry.To rule out any relay/config cause, I verified the relay side is fully correct via
/query:kind:10100exists withrespond_to: "anyone"andchannel_idscontaining a channel the mentioning user is also in;kind:13534) and the channel member list (kind:39002);With all of that in place the agent still never appears in the
@picker on any device except the one that manages it — because the pre-filter above discards it before eligibility is considered. So there is no relay-side workaround; it is purely the client-side ordering described in the title.One adjacent note for self-hosted setups: agents also aren't added to the relay member list automatically (only humans, via invite-claim), so an owner has to admit the agent (kind:9030) before it can publish its
kind:10100at all. That's a separate prerequisite, but worth mentioning since it blocks reproducing the directory-eligibility path in a closed relay.(Same symptom as #2508.)
micspiral commentedon Aug 13, 2026
Confirming this is still fully reproducible on 0.5.11 (
9e0c6b4), and adding what I think is the reason it keeps looking fixed when it isn't.Reproduction
Three machines, three distinct owner pubkeys, one community. Agents run under Desktop on machine A. From B and C, in a channel where the agent is a
role=botmember and actively posting:@autocomplete;ptags, so the agent is never woken.Verified on the wire — the sent event has
["p", …]absent entirely. Settingrespond_totoallowlist(with the viewer's pubkey) oranyone, restarting the harness, and re-adding channel membership change nothing. The author gate is downstream of the mention ever arriving, so it is not reachable.Why #4913's fix doesn't take effect
#4913 rewrote the consumer correctly —
isAgentIdentityInAllowedList, exact-channel authorization, allowlist handling. The problem is the data it consumes.Both eligibility branches in
agentAutocompleteEligibility.tsread aRelayAgent, which comes only fromlist_relay_agents→{"kinds":[10100]}(desktop/src-tauri/src/commands/agent_discovery.rs:1046). Onorigin/main:Nothing publishes an agent profile. The only kind:10100 writer in the tree is
buzz channels set-add-policy(crates/buzz-cli/src/commands/channels.rs:1051), whose body is{"channel_add_policy": …}.So
list_relay_agentsreturns nothing usable,mentionableAgentPubkeyscollapses to the viewer's own managed agents, and every foreign agent is dropped at theaddCandidategate — beforeshouldHideAgentFromMentionsand before the authorization logic #4913 added. Exactly the ordering this issue reported in July; #4913 fixed the policy but not the precedence-with-empty-input problem.The reason this reads as green in CI: the e2e mock synthesizes the directory records (
syncMockRelayAgentsFromManagedAgents,desktop/src/testing/e2eBridge.ts:3617) with no production counterpart. The mention specs pass against fabricated 10100 entries that no running system ever emits. Credit to @jjalora — this is called out in #5546 and it is the crux.On the open PRs
~20 open, none reviewed. Two look complementary rather than competing:
channel_add_policyforward from the current head before republishing, and skips the publish entirely if that read fails rather than fabricating a policy. That matters:handle_agent_profile(crates/buzz-relay/src/handlers/side_effects.rs:1171) hard-requires the field. (feat(acp): self-publish kind:10100 agent profile for Desktop discovery #5691 is a lighter opt-in variant of the same idea; fix(acp,core,relay): publish agent profiles on kind:10100 and move channel-add policy to 10101 #4994 instead moves policy to 10101 to end the kind sharing, which is arguably cleaner but is now conflicted.)A producer alone leaves Desktop-managed agents (like ours, kind:30177, never self-publishing) still invisible, and a union alone has nothing to union for externally-hosted agents. Landing one without the other fixes half the matrix.
Still uncovered
MembersSidebar.tsx:297applies the same gate to add-member search, so even with mentions fixed a non-owner cannot add a shared agent to a channel — the second half of this issue's title. #5546 explicitly leaves it untouched.Happy to test any candidate against our three-machine setup; we have a live reproduction and are blocked on it today.
fix(desktop): let channel-member agents reach the mention picker
fix(desktop): let channel-member agents reach the mention picker