diff --git a/CHANGELOG.md b/CHANGELOG.md index 658ba8598..a1d3f035f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Browser: extension mode recovers when only one tab is attached (stale targetId fallback). - Browser: fix `tab not found` for extension relay snapshots/actions when Playwright blocks `newCDPSession` (use the single available Page). - Telegram: add bidirectional reaction support with configurable notifications and agent guidance. (#964) — thanks @bohdanpodvirnyi. +- Discord: allow allowlisted guilds without channel lists to receive messages when `groupPolicy="allowlist"`. — thanks @thewilloftheshadow. ## 2026.1.14-1 diff --git a/docs/channels/discord.md b/docs/channels/discord.md index 689d84dde..4f7590c8b 100644 --- a/docs/channels/discord.md +++ b/docs/channels/discord.md @@ -191,7 +191,7 @@ Notes: - Your config requires mentions and you didn’t mention it, or - Your guild/channel allowlist denies the channel/user. - **`requireMention: false` but still no replies**: - - `channels.discord.groupPolicy` defaults to **allowlist**; set it to `"open"` or explicitly list channels under `channels.discord.guilds..channels`. + - `channels.discord.groupPolicy` defaults to **allowlist**; set it to `"open"` or add a guild entry under `channels.discord.guilds` (optionally list channels under `channels.discord.guilds..channels` to restrict). - `requireMention` must live under `channels.discord.guilds` (or a specific channel). `channels.discord.requireMention` at the top level is ignored. - **Permission audits** (`channels status --probe`) only check numeric channel IDs. If you use slugs/names as `channels.discord.guilds.*.channels` keys, the audit can’t verify permissions. - **DMs don’t work**: `channels.discord.dm.enabled=false`, `channels.discord.dm.policy="disabled"`, or you haven’t been approved yet (`channels.discord.dm.policy="pairing"`). @@ -352,6 +352,7 @@ Allowlist matching notes: - Prefixes like `discord:`/`user:` (users) and `channel:` (group DMs) are supported. - Use `*` to allow any sender/channel. - When `guilds..channels` is present, channels not listed are denied by default. +- When `guilds..channels` is omitted, all channels in the allowlisted guild are allowed. Native command notes: - The registered commands mirror Clawdbot’s chat commands. diff --git a/docs/start/faq.md b/docs/start/faq.md index 5ef6ad161..d92daf367 100644 --- a/docs/start/faq.md +++ b/docs/start/faq.md @@ -1542,10 +1542,11 @@ See [Streaming](/concepts/streaming). ### Discord doesn’t reply in my server even with `requireMention: false`. Why? `requireMention` only controls mention‑gating **after** the channel passes allowlists. -By default `channels.discord.groupPolicy` is **allowlist**, so guild channels must be explicitly enabled. +By default `channels.discord.groupPolicy` is **allowlist**, so guilds must be explicitly enabled. +If you set `channels.discord.guilds..channels`, only the listed channels are allowed; omit it to allow all channels in the guild. Fix checklist: -1) Set `channels.discord.groupPolicy: "open"` **or** add the guild/channel allowlist. +1) Set `channels.discord.groupPolicy: "open"` **or** add a guild allowlist entry (and optionally a channel allowlist). 2) Use **numeric channel IDs** in `channels.discord.guilds..channels`. 3) Put `requireMention: false` **under** `channels.discord.guilds` (global or per‑channel). Top‑level `channels.discord.requireMention` is not a supported key. diff --git a/src/discord/monitor.test.ts b/src/discord/monitor.test.ts index 3b2b21ac3..adb19820b 100644 --- a/src/discord/monitor.test.ts +++ b/src/discord/monitor.test.ts @@ -215,6 +215,7 @@ describe("discord groupPolicy gating", () => { expect( isDiscordGroupAllowedByPolicy({ groupPolicy: "open", + guildAllowlisted: false, channelAllowlistConfigured: false, channelAllowed: false, }), @@ -225,26 +226,40 @@ describe("discord groupPolicy gating", () => { expect( isDiscordGroupAllowedByPolicy({ groupPolicy: "disabled", + guildAllowlisted: true, channelAllowlistConfigured: true, channelAllowed: true, }), ).toBe(false); }); - it("blocks allowlist when no channel allowlist configured", () => { + it("blocks allowlist when guild is not allowlisted", () => { expect( isDiscordGroupAllowedByPolicy({ groupPolicy: "allowlist", + guildAllowlisted: false, channelAllowlistConfigured: false, channelAllowed: true, }), ).toBe(false); }); + it("allows allowlist when guild allowlisted but no channel allowlist", () => { + expect( + isDiscordGroupAllowedByPolicy({ + groupPolicy: "allowlist", + guildAllowlisted: true, + channelAllowlistConfigured: false, + channelAllowed: true, + }), + ).toBe(true); + }); + it("allows allowlist when channel is allowed", () => { expect( isDiscordGroupAllowedByPolicy({ groupPolicy: "allowlist", + guildAllowlisted: true, channelAllowlistConfigured: true, channelAllowed: true, }), @@ -255,6 +270,7 @@ describe("discord groupPolicy gating", () => { expect( isDiscordGroupAllowedByPolicy({ groupPolicy: "allowlist", + guildAllowlisted: true, channelAllowlistConfigured: true, channelAllowed: false, }), diff --git a/src/discord/monitor/allow-list.ts b/src/discord/monitor/allow-list.ts index aa95e6a4f..31a3d1042 100644 --- a/src/discord/monitor/allow-list.ts +++ b/src/discord/monitor/allow-list.ts @@ -197,13 +197,15 @@ export function resolveDiscordShouldRequireMention(params: { export function isDiscordGroupAllowedByPolicy(params: { groupPolicy: "open" | "disabled" | "allowlist"; + guildAllowlisted: boolean; channelAllowlistConfigured: boolean; channelAllowed: boolean; }): boolean { - const { groupPolicy, channelAllowlistConfigured, channelAllowed } = params; + const { groupPolicy, guildAllowlisted, channelAllowlistConfigured, channelAllowed } = params; if (groupPolicy === "disabled") return false; if (groupPolicy === "open") return true; - if (!channelAllowlistConfigured) return false; + if (!guildAllowlisted) return false; + if (!channelAllowlistConfigured) return true; return channelAllowed; } diff --git a/src/discord/monitor/message-handler.preflight.ts b/src/discord/monitor/message-handler.preflight.ts index 657c83a5e..ca7ba5131 100644 --- a/src/discord/monitor/message-handler.preflight.ts +++ b/src/discord/monitor/message-handler.preflight.ts @@ -260,6 +260,7 @@ export async function preflightDiscordMessage( isGuildMessage && !isDiscordGroupAllowedByPolicy({ groupPolicy: params.groupPolicy, + guildAllowlisted: Boolean(guildInfo), channelAllowlistConfigured, channelAllowed, }) diff --git a/src/discord/monitor/native-command.ts b/src/discord/monitor/native-command.ts index 3dafe17c7..ccba87475 100644 --- a/src/discord/monitor/native-command.ts +++ b/src/discord/monitor/native-command.ts @@ -448,6 +448,7 @@ async function dispatchDiscordCommandInteraction(params: { const channelAllowed = channelConfig?.allowed !== false; const allowByPolicy = isDiscordGroupAllowedByPolicy({ groupPolicy: discordConfig?.groupPolicy ?? "open", + guildAllowlisted: Boolean(guildInfo), channelAllowlistConfigured, channelAllowed, });