CoderClaw treats group chats consistently across surfaces: WhatsApp, Telegram, Discord, Slack, Signal, iMessage, Microsoft Teams.
CoderClaw “lives” on your own messaging accounts. There is no separate WhatsApp bot user. If you are in a group, CoderClaw can see that group and respond there.
Default behavior:
groupPolicy: "allowlist").Translation: allowlisted senders can trigger CoderClaw by mentioning it.
TL;DR
- DM access is controlled by
*.allowFrom.- Group access is controlled by
*.groupPolicy+ allowlists (*.groups,*.groupAllowFrom).- Reply triggering is controlled by mention gating (
requireMention,/activation).
Quick flow (what happens to a group message):
groupPolicy? disabled -> drop
groupPolicy? allowlist -> group allowed? no -> drop
requireMention? yes -> mentioned? no -> store for context only
otherwise -> reply
If you want…
| Goal | What to set |
|---|---|
| Allow all groups but only reply on @mentions | groups: { "*": { requireMention: true } } |
| Disable all group replies | groupPolicy: "disabled" |
| Only specific groups | groups: { "<group-id>": { ... } } (no "*" key) |
| Only you can trigger in groups | groupPolicy: "allowlist", groupAllowFrom: ["+1555..."] |
agent:<agentId>:<channel>:group:<id> session keys (rooms/channels use agent:<agentId>:<channel>:channel:<id>).:topic:<threadId> to the group id so each topic has its own session.Yes — this works well if your “personal” traffic is DMs and your “public” traffic is groups.
Why: in single-agent mode, DMs typically land in the main session key (agent:main:main), while groups always use non-main session keys (agent:main:<channel>:group:<id>). If you enable sandboxing with mode: "non-main", those group sessions run in Docker while your main DM session stays on-host.
This gives you one agent “brain” (shared workspace + memory), but two execution postures:
If you need truly separate workspaces/personas (“personal” and “public” must never mix), use a second agent + bindings. See Multi-Agent Routing.
Example (DMs on host, groups sandboxed + messaging-only tools):
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // groups/channels are non-main -> sandboxed
scope: "session", // strongest isolation (one container per group/channel)
workspaceAccess: "none",
},
},
},
tools: {
sandbox: {
tools: {
// If allow is non-empty, everything else is blocked (deny still wins).
allow: ["group:messaging", "group:sessions"],
deny: ["group:runtime", "group:fs", "group:ui", "nodes", "cron", "gateway"],
},
},
},
}
Want “groups can only see folder X” instead of “no host access”? Keep workspaceAccess: "none" and mount only allowlisted paths into the sandbox:
{
agents: {
defaults: {
sandbox: {
mode: "non-main",
scope: "session",
workspaceAccess: "none",
docker: {
binds: [
// hostPath:containerPath:mode
"/home/user/FriendsShared:/data:ro",
],
},
},
},
},
}
Related:
displayName when available, formatted as <channel>:<token>.#room is reserved for rooms/channels; group chats use g-<slug> (lowercase, spaces -> -, keep #@+._-).Control how group/room messages are handled per channel:
{
channels: {
whatsapp: {
groupPolicy: "disabled", // "open" | "disabled" | "allowlist"
groupAllowFrom: ["+15551234567"],
},
telegram: {
groupPolicy: "disabled",
groupAllowFrom: ["123456789"], // numeric Telegram user id (wizard can resolve @username)
},
signal: {
groupPolicy: "disabled",
groupAllowFrom: ["+15551234567"],
},
imessage: {
groupPolicy: "disabled",
groupAllowFrom: ["chat_id:123"],
},
msteams: {
groupPolicy: "disabled",
groupAllowFrom: ["[email protected]"],
},
discord: {
groupPolicy: "allowlist",
guilds: {
GUILD_ID: { channels: { help: { allow: true } } },
},
},
slack: {
groupPolicy: "allowlist",
channels: { "#general": { allow: true } },
},
matrix: {
groupPolicy: "allowlist",
groupAllowFrom: ["@owner:example.org"],
groups: {
"!roomId:example.org": { allow: true },
"#alias:example.org": { allow: true },
},
},
},
}
| Policy | Behavior |
|---|---|
"open" |
Groups bypass allowlists; mention-gating still applies. |
"disabled" |
Block all group messages entirely. |
"allowlist" |
Only allow groups/rooms that match the configured allowlist. |
Notes:
groupPolicy is separate from mention-gating (which requires @mentions).groupAllowFrom (fallback: explicit allowFrom).channels.discord.guilds.<id>.channels.channels.slack.channels.channels.matrix.groups (room IDs, aliases, or names). Use channels.matrix.groupAllowFrom to restrict senders; per-room users allowlists are also supported.channels.discord.dm.*, channels.slack.dm.*)."123456789", "telegram:123456789", "tg:123456789") or usernames ("@alice" or "alice"); prefixes are case-insensitive.groupPolicy: "allowlist"; if your group allowlist is empty, group messages are blocked.Quick mental model (evaluation order for group messages):
groupPolicy (open/disabled/allowlist)*.groups, *.groupAllowFrom, channel-specific allowlist)requireMention, /activation)Group messages require a mention unless overridden per group. Defaults live per subsystem under *.groups."*".
Replying to a bot message counts as an implicit mention (when the channel supports reply metadata). This applies to Telegram, WhatsApp, Slack, Discord, and Microsoft Teams.
{
channels: {
whatsapp: {
groups: {
"*": { requireMention: true },
"[email protected]": { requireMention: false },
},
},
telegram: {
groups: {
"*": { requireMention: true },
"123456789": { requireMention: false },
},
},
imessage: {
groups: {
"*": { requireMention: true },
"123": { requireMention: false },
},
},
},
agents: {
list: [
{
id: "main",
groupChat: {
mentionPatterns: ["@coderclaw", "coderclaw", "\\+15555550123"],
historyLimit: 50,
},
},
],
},
}
Notes:
mentionPatterns are case-insensitive regexes.agents.list[].groupChat.mentionPatterns (useful when multiple agents share a group).mentionPatterns are configured).channels.discord.guilds."*" (overridable per guild/channel).messages.groupChat.historyLimit for the global default and channels.<channel>.historyLimit (or channels.<channel>.accounts.*.historyLimit) for overrides. Set 0 to disable.Some channel configs support restricting which tools are available inside a specific group/room/channel.
tools: allow/deny tools for the whole group.toolsBySender: per-sender overrides within the group (keys are sender IDs/usernames/emails/phone numbers depending on the channel). Use "*" as a wildcard.Resolution order (most specific wins):
toolsBySender matchtools"*") toolsBySender match"*") toolsExample (Telegram):
{
channels: {
telegram: {
groups: {
"*": { tools: { deny: ["exec"] } },
"-1001234567890": {
tools: { deny: ["exec", "read", "write"] },
toolsBySender: {
"123456789": { alsoAllow: ["exec"] },
},
},
},
},
},
}
Notes:
guilds.*.channels.*, Slack channels.*, MS Teams teams.*.channels.*).When channels.whatsapp.groups, channels.telegram.groups, or channels.imessage.groups is configured, the keys act as a group allowlist. Use "*" to allow all groups while still setting default mention behavior.
Common intents (copy/paste):
{
channels: { whatsapp: { groupPolicy: "disabled" } },
}
{
channels: {
whatsapp: {
groups: {
"[email protected]": { requireMention: true },
"[email protected]": { requireMention: false },
},
},
},
}
{
channels: {
whatsapp: {
groups: { "*": { requireMention: true } },
},
},
}
{
channels: {
whatsapp: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15551234567"],
groups: { "*": { requireMention: true } },
},
},
}
Group owners can toggle per-group activation:
/activation mention/activation alwaysOwner is determined by channels.whatsapp.allowFrom (or the bot’s self E.164 when unset). Send the command as a standalone message. Other surfaces currently ignore /activation.
Group inbound payloads set:
ChatType=groupGroupSubject (if known)GroupMembers (if known)WasMentioned (mention gating result)MessageThreadId and IsForum.The agent system prompt includes a group intro on the first turn of a new group session. It reminds the model to respond like a human, avoid Markdown tables, and avoid typing literal \n sequences.
chat_id:<id> when routing or allowlisting.imsg chats --limit 20.chat_id.See Group messages for WhatsApp-only behavior (history injection, mention handling details).