Repository navigation
feat(buzz-mcp): let agents make announce channels with join_role - #1996
Merged
Merged
Conversation
channel_create and channel_update now take join_role (member or guest), so an agent with only the in-app tools can make an announce channel: an open channel where anyone can join and read, but only members can post. channel_get shows "join as guest" for such a channel. The relay takes join_role only on kind:9002, so channel_create sets it with a second event after the channel exists, and after the template's agents are added: an add with no role tag gives join_role, so those agents would otherwise join as guests. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
…nels From Auto's review of #1996: - members: an add with no role gets the channel's join_role, so on an announce channel the person becomes a guest. The answer now says "added <key> as guest" (any role the roster shows other than member). - channel_create and channel_update refuse join_role guest on a private channel, as the channel details UI does not offer it there. - The join_role description says it also applies to adds with no role. - The test relay gives a no-role add the channel's join_role, and new tests cover guest with a refused Canvas and an unreadable channel. - Rename the join(args) helper to joinRoleArg. Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Logan Johnson <loganj@squareup.com>
This comment has been minimized.
This comment has been minimized.
loganj
marked this pull request as ready for review
October 30, 2026 18:52
kalvinnchau
approved these changes
Oct 30, 2026
kalvinnchau
left a comment
Contributor
There was a problem hiding this comment.
🤖 Code review at 0d06af4: no findings. join_role is validated before anything is published, set after template agents are added so they stay members, and the relay always publishes an explicit join_role tag so the update read-back check holds for member too. vitest src/buzz-mcp (154 passed) and biome check pass locally.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Agents that use only the in-app Buzz tools can now make an announce channel: an open channel where anyone can join and read, but only members can post.
channel_updatetakesjoin_role: "member" | "guest". It sends["join_role", ...]on kind:9002, the same tag thebuzz channels update --join-roleCLI and the channel details UI (feat(channels): control participation and preserve guest reading #1882) send.channel_createtakes the samejoin_role. The relay acceptsjoin_roleonly on kind:9002, not on kind:9007, so the tool sets it with a second event once the channel exists.channel_getshowsjoin as guestfor such a channel, so an agent can check the result.members: an add with no role gets the channel'sjoin_role, so on an announce channel that person becomes a guest. The answer now saysadded <key> as guestinstead of a bareadded <key>.join_role: guestis refused on a private channel, as the channel details UI does not offer it there.Why
The relay (block/buzz#8143) and the app UI (#1882) support announce channels, and the
buzzCLI can set them, butchannel_createandchannel_updatehad no way to setjoin_role. Agents running on the in-app MCP tools could not make one.Details
join_roleis set last, after the template's agents are added. A kind:9000 add with noroletag gives the channel'sjoin_role, so if the channel were an announce channel first, the template's agents would join as guests and could not post.memberis the default, sochannel_createwithjoin_role: "member"sends no second event.join_roleevent, the channel still exists; the answer sayscreated <id>and thenjoin_role not set: <reason>.memberandguestare refused before anything is published, matching the relay's own validation.Testing
pnpm exec vitest run src/buzz-mcpat 0d06af4: 154 passed. New tests cover update to guest and back; create with a template (event order 9007, 9000, 9002, and the template agent stays a member); a later no-role add reported as guest; guest with a refused Canvas and with an unreadable channel; a refused 9002 on create; and invalid or private-channel values. The test relay now gives a no-role add the channel'sjoin_role, as the relay does.pnpm run typecheckandbiome checkpass.ghcr.io/block/buzz:main, revision 75854111b, run locally), through the real tool handlers with the standalonenodeClientat 0d06af4:channel_create {visibility: open, join_role: guest}→created <id>/new people join as guests; the relay's kind:39000 has["restricted"]and["join_role","guest"], andchannel_getshowsjoin as guest.channel_join→you: guest; itssendis refused:restricted: only members can post in this channel. The owner'ssendsucceeds.members {add, role: member}→added <key> as member, and that agent can then post.members {add}with no role →added <key> as guest.channel_update {join_role: member}→updated, andjoin as guestis gone; back toguest→updated. A non-admin'schannel_update {join_role}is refused by the relay (actor not authorized ... join_role).channel_createwith a template agent andjoin_role: guest→ the agent is added first and isyou: member, and it can post. The channel then showsjoin as guest.channel_create {visibility: private, join_role: guest}→ refused before publishing.app_agent_publish). It signs and posts the same events without a kind or tag allowlist.🤖 Generated with Claude Code