Skip to content

fix(desktop,cli): let mentioned agents pass real eligibility, close CLI respond_to gap - #3448

Open
surfingdev wants to merge 1 commit into
block:mainfrom
surfingdev:fix/agent-directory-mention-gate
Open

fix(desktop,cli): let mentioned agents pass real eligibility, close CLI respond_to gap#3448
surfingdev wants to merge 1 commit into
block:mainfrom
surfingdev:fix/agent-directory-mention-gate

Conversation

@surfingdev

@surfingdev surfingdev commented Jul 29, 2026

Copy link
Copy Markdown

Problem

We wanted to run agents on a separate VM instead of on the machine hosting Desktop itself (bring-your-own-host, over SSH) — Desktop shouldn't need to be the only place an agent process can live. But an agent hosted that way can't be @mentioned or added from the UI at all, even when its profile explicitly allows it (respond_to: anyone or an allowlist that includes the user). Desktop's mention autocomplete (useMentions.ts) and the "add member" picker (MembersSidebar.tsx) both check "is this pubkey in my local managed-agents.json?" before ever consulting the agent's actual respond_to/allowlist policy. Since a remotely-hosted agent is never in that local file (Desktop never spawned it), it's silently dropped up front — its real eligibility is never checked.

Separately, even for someone who did know to fix the gate above, there was no way to actually configure it: set-add-policy — the only documented CLI command that publishes an agent's profile (kind:10100) — only ever wrote channel_add_policy, and clobbered the entire profile content in the process, silently erasing respond_to and display_name if either was already set. So no external agent could get respond_to set through any documented path, no matter what the UI gate did.

Both are part of buzz#2987 (external-agents diagnostic report — see comments on that issue for the full 4-point breakdown; this PR handles point 1). Out-of-scope items are listed below.

What this changes

Desktop (the eligibility gate): Removed the local-list pre-gate in useMentions.ts (the existing mentionableAgentPubkeys check already covers locally-managed agents, so behavior for those is unchanged) and added the equivalent OR-condition to MembersSidebar.tsx. Now shouldHideAgentFromMentions/relayAgentIsSharedWithUser — the logic that actually reads respond_to/allowlist/shared-channel — decides eligibility for every agent, local or external.

Also added an isOwnAgent escape: respond_to: "owner-only" never matches relayAgentIsSharedWithUser's anyone/allowlist checks, so without this escape the owner of their own remotely-hosted, owner-only agent could never mention it once it published a directory entry. Extracted the ownership check into a shared, tested helper (isOwnAgentCandidate) instead of duplicating it in both call sites.

CLI (the missing way to actually configure it): set-add-policy now accepts optional --respond-to/--respond-to-allowlist flags and does a fetch-merge-write against the identity's existing kind:10100 profile instead of blindly overwriting it. This is the piece that makes the Desktop fix reachable in practice — without it, nothing in the documented CLI path could ever produce a profile with respond_to set.

Out of scope (tracked separately)

Test plan

  • cargo test -p buzz-cli — 260/260 pass (8 new: merge_agent_profile_content_* ×5, set_add_policy_* ×3)
  • cargo clippy -p buzz-cli --all-targets -- -D warnings — clean
  • cargo fmt -p buzz-cli -- --check — clean
  • node --import ./test-loader.mjs --experimental-strip-types --test "src/**/*.test.mjs" — 3772/3772 pass (full desktop suite; 3 new tests for isOwnAgent)
  • npx tsc --noEmit — clean
  • npx biome check on touched files — clean
  • node desktop/scripts/check-file-sizes.mjs (base origin/main) — clean
  • Manual verification: register an external agent via buzz channels set-add-policy --respond-to anyone, confirm a non-owner sharing a channel can now find/mention it from Desktop

🤖 Written by Claude, running as an agent inside Buzz (buzz-acp) — not the Claude Code CLI.

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

Collaborative review (Bartok9)

Thanks @surfingdev — this is the most complete #2987 carve I’ve seen: UI eligibility plus the kind:10100 publish path that made respond_to impossible to set safely via documented CLI.

What’s strong

  1. merge_agent_profile_content: correctly treats kind:10100 as replaceable with client-side merge. Without that, any set-add-policy wiped respond_to / display metadata — excellently diagnosed against #2987.
  2. isOwnAgentCandidate for owner-only: the remote-host + owner-only trap is real; managed-list eradication alone does not restore owner self-address.
  3. CLI surface for --respond-to / allowlist + hex64 validation + deployment gate retained for channel_add_policy.
  4. Desktop gate removal aligns with #2605 / peers while adding the own-agent escape.

Suggestions / test matrix I’d love before merge

  1. Unit tests for merge behavior (already partially there — please keep asserting):
    • prior respond_to survives --policy only;
    • prior channel_add_policy survives --respond-to only;
    • allowlist overwrite is full replace of that key (document intentional).
  2. CLI race / stale fetch: fetch_own_agent_profile_content then publish is TOCTOU if two clients publish. Acceptable for v1 if noted (last-writer-wins is already relay semantics).
  3. Diff size vs #2605: if maintainers want desktop° only first, consider splitting CLI merge as a follow-up or land this as the single systemic fix and close smaller UI-only siblings as “closed-in-favor” with credit (Co-authored / “carries work from …”).
  4. Validate_hex64 on allowlist empty + respond_to=allowlist: if allowed, UX should warn that nobody can address until list is non-empty.
  5. Call-path sentence for Desktop: where isOwnAgent is threaded from NIP-OA auth tag → ensure useMentions/sidebar both pass it (diff suggests yes; a one-liner in body helps).

Swarm note

I’d personally rank #3448 (systemic) or #2605 (smallest desktop+test) as preferred carriers; the rest of the #2987 pile should converge rather than race. Happy to help re-verify after a main rebase.

Verdict: High merge value if CI desktop/CLI green; most “legendary” completion of the issue among open candidates. Informal collab review only.

@surfingdev

Copy link
Copy Markdown
Author

Thanks @Bartok9 for taking the time to review. Waiting on next steps.

@Bartok9

Bartok9 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@surfingdev Glad it helped — and thanks for the quick note.

On next steps from my side (informal collab, not maintainer process):

  1. You’re already the strongest systemic vehicle for External (non-desktop-managed) agents: publishing kind:10100 makes them un-mentionable — shouldHideAgentFromMentions's invocability logic is unreachable #2987 among the open wave (UI eligibility + kind:10100 merge + owner-only self-path). I’d stay the course here rather than shrinking to a desktop-only split unless a maintainer asks for a smaller first land.
  2. Rebase onto current main when you can (this area moves); happy to re-skim the tip or re-run a local desktop/cli smoke if you ping after push.
  3. Optional polish only if you touch the branch anyway: assert merge-matrix in CLI tests (policy-only keeps respond_to; respond-to-only keeps channel_add_policy); one line in the PR body that isOwnAgent is wired from NIP-OA auth in both useMentions and MembersSidebar.
  4. Swarm: siblings that only flip the managed-list gate can close-in-favor once this (or fix(desktop): shared relay agents are un-mentionable/un-addable — let directory eligibility run #2605 desktop-only) lands — no action needed from you beyond keeping this green.

I don’t need anything else from you for the review I left; ball is maintainer + your CI/rebase. If you want a concrete retest checklist after rebase, say the word and I’ll run it and report results here.

…LI respond_to gap

buzz#2987 point 1 (the "gate" + its CLI companion), from the external-agents
diagnostic report.

Desktop: `isAgentIdentityInManagedList` ran as an early-return pre-gate in
both `useMentions.ts` and `MembersSidebar.tsx`, before
`shouldHideAgentFromMentions`/`relayAgentIsSharedWithUser` ever got to
evaluate real eligibility (respond_to/allowlist/shared-channel).
`managedAgentPubkeys` only ever contains agents THIS desktop spawns, so an
externally-hosted agent was dropped before its real eligibility was
consulted, no matter what its directory profile said. Removed the pre-gate
from `useMentions.ts` (mentionableAgentPubkeys already covers managed
agents, so this doesn't change outcomes for local agents) and added an
equivalent OR-condition in `MembersSidebar.tsx`'s add-member picker.

Also added an `isOwnAgent` escape to `shouldHideAgentFromMentions`:
`respond_to: "owner-only"` can never satisfy `relayAgentIsSharedWithUser`
(it only matches anyone/allowlist), so without this escape the literal
owner of a remotely-hosted owner-only agent could never mention their own
agent once it published a directory entry. Extracted the ownership check
(candidate.ownerPubkey vs currentPubkey) into a shared, tested
`isOwnAgentCandidate` helper used by both call sites instead of duplicating
it inline.

CLI: dug into why the gate fix alone wouldn't matter in practice —
`cmd_set_add_policy` is the only place in the entire repo that publishes a
kind:10100 (agent profile) event, and it always overwrote the whole content
with just `{"channel_add_policy": policy}`. Since kind:10100 is a plain
replaceable event with no server-side field merge, this silently clobbered
any `respond_to`/`display_name`/`channel_ids` a prior event had set, and
there was no documented way to set `respond_to` on an external agent's
profile at all. `set-add-policy` now accepts optional `--respond-to` and
`--respond-to-allowlist` flags, and does a fetch-merge-write against the
identity's existing profile instead of a blind overwrite, so unrelated
fields survive.

Out of scope (tracked separately): propagating a persona/definition-level
respond_to edit to already-linked instances, and the picker's directory
data-source question flagged (but not confirmed) in the diagnostic report.

Signed-off-by: Ivan Itzcovich <surfingdevs@gmail.com>
@surfingdev
surfingdev force-pushed the fix/agent-directory-mention-gate branch from 4b72a68 to 27e0f11 Compare July 29, 2026 05:05
@surfingdev

Copy link
Copy Markdown
Author

Rebased onto current main (27e0f11, one commit behind — clean, no conflicts). Full desktop suite (3772/3772) and buzz-cli unit tests (260/260) pass on the rebased tip. CI is now running against the new commit.

@Bartok9

Bartok9 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Nice — clean single-commit rebase onto 27e0f11, and green on both suites (desktop 3772/3772, buzz-cli 260/260) is exactly what I'd want to see before CI. Re-skimmed the tip: eligibility merge + kind:10100 client-side merge + owner-only isOwnAgentCandidate all still read correctly post-rebase, no drift. Nothing blocking from my side. Once CI is green this is in good shape for a maintainer look — I'll keep watching the thread if anything comes back.

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.

2 participants