Skip to content

feat(acp): publish kind:10100 agent directory profile - #4713

Open
dexsynccom wants to merge 2 commits into
block:mainfrom
dexsynccom:fix/agent-mention-eligibility
Open

feat(acp): publish kind:10100 agent directory profile#4713
dexsynccom wants to merge 2 commits into
block:mainfrom
dexsynccom:fix/agent-mention-eligibility

Conversation

@dexsynccom

@dexsynccom dexsynccom commented Aug 4, 2026

Copy link
Copy Markdown

Summary

Publishes the kind:10100 agent directory profile from the ACP harness. Nothing in the tree ever published one, so the directory was permanently empty — while desktop and mobile both consume it for mention eligibility and the relay ingests it with a users-table side effect.

Rebased onto current main; scope reduced. This PR originally also carried a desktop-side mention-gate fix. #4913 has since landed and supersedes that half with a more thorough implementation (exact-channel authorization, fail-closed DM/context handling, cached-row reauthorization), so the desktop commit is dropped.

That makes this PR the enabling half of #4913: getMentionableAgentPubkeys admits relay agents via relayAgentCanRespondInChannel, which reads respond_to, respond_to_allowlist, and channel_ids from kind:10100. With no publisher, that path can never admit anyone — a harness-run agent stays invisible in mention autocomplete to everyone except its own owner (who is admitted via the managed-agent set instead).

Changes

feat(acp): publish kind:10100 agent directory profile

  • Publishes at the presence-online readiness boundary (after channel subscriptions resolve, so channel_ids reflects the live set) and republishes on membership-notification changes in both directions.
  • Content carries the cross-client contract fields already parsed by agents_from_events (desktop) and AgentDirectoryEntry.fromEvent (mobile): respond_to, respond_to_allowlist, channel_ids, channel_add_policy. Collections are normalized and sorted so republishes are deterministic.
  • Best-effort and non-fatal, matching the adjacent presence publish: a failure logs and self-heals on the next restart or membership change.
  • Discovery metadata only — author_allowed remains the enforcement point, and clients should treat this as advisory.

fix(acp): don't clobber operator channel_add_policy on republish

  • kind:10100 is replaceable, and buzz channels set-agent-policy writes the same kind carrying only channel_add_policy. A hardcoded value would silently reset an operator's stricter owner_only/nobody back to anyone on the next restart or membership change.
  • The advertised value now resolves from BUZZ_ACP_CHANNEL_ADD_POLICY, defaulting to the relay's own column default.

Validation

  • just ci green on the rebased branch.
  • Unit tests cover the cross-client field contract, the exact respond_to strings clients compare, and the policy override.
  • Verified end to end on a self-hosted deployment: with the harness publishing, a non-owner member could mention a harness-run agent and receive a reply; without it, the identical mention produced no p tag and the agent never saw the message (its #p-filtered subscription never matched).

🤖 Generated with Claude Code

dexsynccom and others added 2 commits August 13, 2026 08:36
Clients already consume kind:10100 for mention eligibility (desktop
list_relay_agents, mobile agentDirectoryProvider) and the relay ingests
it with a users-table side effect, but nothing ever published it — so an
agent's respond_to/allowlist policy and channel set were invisible to
other users' clients, and respond_to=anyone had no effect on who could
see the agent in mention autocomplete.

Publish the profile at the presence-online readiness boundary and
republish whenever a membership notification changes the subscribed
channel set. Content carries the cross-client contract fields:
respond_to, respond_to_allowlist, channel_ids, channel_add_policy.
Discovery metadata only — the author gate (author_allowed) remains the
enforcement point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dexsynccom <rifai@dexsync.com>
kind:10100 is replaceable and `buzz channels set-agent-policy` writes the
same kind carrying only channel_add_policy. The directory publisher hardcoded
"anyone", so every restart or membership change silently reset an operator's
stricter policy (owner_only/nobody) — a security-loosening regression.

Resolve the advertised value from BUZZ_ACP_CHANNEL_ADD_POLICY, defaulting to
the relay's own column default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: dexsynccom <rifai@dexsync.com>
@dexsynccom
dexsynccom force-pushed the fix/agent-mention-eligibility branch from 9e249b0 to 0ddff55 Compare August 13, 2026 07:37
@dexsynccom dexsynccom changed the title fix(agents): make agents mentionable by non-owners (desktop eligibility gate + kind:10100 directory) feat(acp): publish kind:10100 agent directory profile Aug 13, 2026

@wolfyy970 wolfyy970 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Publishing from the running harness is the right ownership boundary, but this head is not safe to merge yet.

  • The channel_add_policy fix does not preserve an operator's saved choice. buzz channels set-add-policy publishes the policy but never sets BUZZ_ACP_CHANNEL_ADD_POLICY. On the next harness start, this code defaults to anyone and writes that value back into the relay database. It still loosens owner_only or nobody.
  • The two commands remain incompatible whole-document writers. The CLI replaces the directory profile with policy-only JSON; the harness replaces it with directory JSON plus whatever policy its process happened to start with. Directory state and channel-add policy need separate authority. The smallest relay change is to treat an absent policy as “leave the stored policy unchanged,” then let the harness omit it.
  • Every membership notification awaits a profile publish in the main event loop. Add and remove in the same second can race Nostr replaceable-event ID ordering, leaving the older channel set as the relay head, and a slow HTTP publish pauses event consumption. Debounce/coalesce refreshes and verify the submitted profile became the current head.
  • For externally hosted agents, this newly publishes the exact respond-to allowlist community-wide. That membership is an access-policy detail, not directory metadata. Keep it in the private policy boundary and advertise only enough public state for routing.

#5546 is solving the same producer seam. I would consolidate on one implementation rather than land two profile publishers with different policy and refresh behavior.

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