Skip to main content
The Notifications feature lets server members subscribe and unsubscribe from notification roles entirely by themselves — no moderator action required. All interaction is ephemeral, so only the member using the command can see the UI.

How it works

1

Run /notifications

Any server member runs /notifications. The bot responds with an ephemeral multi-select dropdown listing every available notification role.
2

Pick your roles

Select or deselect roles in the dropdown. The roles you currently hold are pre-selected. You can choose any combination, including none.
3

Changes apply immediately

When you confirm the selection the bot adds and removes roles in parallel. The message updates to reflect the new state.

Which roles appear

Only roles whose name starts with the 🔔 prefix are shown. This lets server administrators control which roles appear in the dropdown by simply naming them with the bell emoji.
Notifications.ts
const notificationRoles = Effect.fnUntraced(function* (guildId: string) {
  const roles = yield* rolesCache.getForParent(guildId)
  return Array.fromIterable(roles.values()).filter((role) =>
    role.name.startsWith("🔔 "),
  )
})

The notification message

The message function builds the UI component tree that is sent (or updated) in response to the command and each subsequent selection:
Notifications.ts
const message = Effect.fn("Notifications.message")(function* (
  ix: Discord.APIInteraction,
  userRoles?: Array<string>,
) {
  const guildId = ix.guild_id
  if (!guildId) {
    return UI.components(
      [UI.textDisplay("This command can only be used in a server.")],
      { ephemeral: true },
    )
  }

  const roles = yield* notificationRoles(guildId)
  if (roles.length === 0) {
    return UI.components(
      [UI.textDisplay("No notification roles found in this server.")],
      { ephemeral: true },
    )
  }

  userRoles = userRoles ?? ix.member!.roles

  return UI.components(
    [
      UI.textDisplay("Select the notifications you want to receive:"),
      UI.row([
        UI.select({
          custom_id: "notifications_role",
          placeholder: "No notifications selected",
          min_values: 0,
          max_values: roles.length,
          options: roles.map((role) => ({
            label: role.name,
            value: role.id,
            default: userRoles.includes(role.id),
          })),
        }),
      ]),
    ],
    { ephemeral: true },
  )
})
The entire response is ephemeral — other members never see which roles you selected.

Setting up notification roles

To make a role appear in the /notifications dropdown, rename it so its name starts with 🔔 (bell emoji followed by a space). For example:
  • 🔔 Releases
  • 🔔 RFCs
  • 🔔 Community calls
Roles without the prefix are ignored entirely.

Build docs developers (and LLMs) love