@badgerclaw/connect 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SETUP.md CHANGED
@@ -6,7 +6,6 @@ Connect your OpenClaw AI agent to BadgerClaw encrypted chat rooms.
6
6
 
7
7
  - **BadgerClaw iOS app** installed and logged in
8
8
  - **OpenClaw** installed on your machine (`npm install -g openclaw`)
9
- - Both on the same network (not required, just for initial setup)
10
9
 
11
10
  ---
12
11
 
@@ -14,28 +13,24 @@ Connect your OpenClaw AI agent to BadgerClaw encrypted chat rooms.
14
13
 
15
14
  Open the BadgerClaw app on your phone.
16
15
 
17
- 1. Open any room or DM
18
- 2. Type: `/bot create <name>`
19
- - Example: `/bot create jarvis`
20
- 3. BotBadger responds with:
16
+ 1. Open any room or DM with BotBadger
17
+ 2. Type: `/bot new`
18
+ 3. Follow the guided flow to set a bot name and username
19
+ 4. BotBadger responds with a pairing code:
21
20
 
22
21
  ```
23
22
  🦡 Bot created!
24
23
 
25
24
  Name: jarvis
26
- ID: @abc123_jarvis_bot:badger.signout.io
27
-
28
25
  Connect to OpenClaw:
29
- openclaw plugins install @badgerclaw/connect
30
26
  openclaw badgerclaw connect BCK-A8F3-X9K2
31
27
 
32
28
  Code expires in 24 hours.
33
- Run /bot pair jarvis to generate a new code.
34
29
  ```
35
30
 
36
- 4. **Copy the pairing code** (BCK-XXXX-XXXX)
31
+ 5. **Copy the pairing code** (BCK-XXXX-XXXX)
37
32
 
38
- > **Need a new code?** Type `/bot pair jarvis` to regenerate.
33
+ > **Need a new code?** Type `/bot pair <name>` to regenerate.
39
34
 
40
35
  ---
41
36
 
@@ -44,38 +39,42 @@ Run /bot pair jarvis to generate a new code.
44
39
  On your machine (Mac, PC, Linux, Pi), run:
45
40
 
46
41
  ```bash
47
- # From GitHub (current method)
42
+ openclaw plugins install @badgerclaw/connect
43
+ ```
44
+
45
+ Or install from source:
46
+
47
+ ```bash
48
48
  git clone https://github.com/darkstaar4/badgerclaw-plugin.git
49
49
  openclaw plugins install ./badgerclaw-plugin
50
-
51
- # From npm (coming soon)
52
- # openclaw plugins install @badgerclaw/connect
53
50
  ```
54
51
 
55
52
  ---
56
53
 
57
54
  ## Step 3: Connect with Pairing Code
58
55
 
59
- Run the OpenClaw configure wizard:
56
+ ```bash
57
+ openclaw badgerclaw connect BCK-XXXX-XXXX
58
+ ```
59
+
60
+ Or run the full configure wizard:
60
61
 
61
62
  ```bash
62
63
  openclaw configure
63
64
  ```
64
65
 
65
- 1. Select **BadgerClaw** as your channel
66
- 2. Enter your pairing code: `BCK-XXXX-XXXX`
67
- 3. The plugin automatically:
68
- - Validates the code with BadgerClaw servers
69
- - Retrieves your bot's credentials
70
- - Enables end-to-end encryption
71
- - Configures auto-join for room invites
72
- 4. Done! Your agent is connected.
66
+ The plugin automatically:
67
+ - Validates the code with BadgerClaw servers
68
+ - Retrieves your bot's credentials
69
+ - Enables end-to-end encryption
70
+ - Configures auto-join for room invites
71
+ - Sets up auto-reply in group chats
73
72
 
74
73
  ---
75
74
 
76
75
  ## Step 4: Start Chatting
77
76
 
78
- Restart the OpenClaw gateway to apply the new config:
77
+ Restart the OpenClaw gateway:
79
78
 
80
79
  ```bash
81
80
  openclaw gateway restart
@@ -83,30 +82,189 @@ openclaw gateway restart
83
82
 
84
83
  Now in the BadgerClaw app:
85
84
 
86
- 1. **DM your bot** — find it in your contacts (`@xxx_jarvis_bot:badger.signout.io`) and send a message
87
- 2. **Add to a room** — type `/bot add @jarvis` in any room
85
+ 1. **DM your bot** — find it in your contacts and send a message
86
+ 2. **Add to a room** — type `/bot add <name>` in any room
88
87
  3. **Add to a Space** — add the bot to any room inside a Space
89
88
 
90
- Your OpenClaw agent will receive messages and respond through BadgerClaw — fully end-to-end encrypted.
89
+ Your OpenClaw agent will receive messages and respond — fully end-to-end encrypted.
91
90
 
92
91
  ---
93
92
 
94
- ## Troubleshooting
93
+ ## Bot Commands
94
+
95
+ Use these commands in any BadgerClaw room or DM where your bot is present.
96
+
97
+ | Command | Description |
98
+ |---------|-------------|
99
+ | `/bot help` | Show all available commands |
100
+ | `/bot talk on` | **Enable auto-reply** — bot responds to every message without needing an @mention. Great for 1-on-1 rooms. |
101
+ | `/bot talk off` | **Disable auto-reply** — bot only responds when @mentioned. Use in busy group rooms. |
102
+ | `/bot add <name>` | Invite a bot to the current room (e.g. `/bot add jarvis`) |
103
+ | `/bot list` | List all your bots and their connection status |
104
+
105
+ ### How Auto-Reply Works
106
+
107
+ - **New installs:** Auto-reply is **ON by default** in all rooms
108
+ - **Per-room toggle:** `/bot talk on` and `/bot talk off` override the default for that specific room
109
+ - **@mentions always work:** Even with auto-reply off, the bot responds when @mentioned
110
+
111
+ ---
112
+
113
+ ## Group Chat Configuration
114
+
115
+ ### Default Behavior
116
+
117
+ When you install BadgerClaw with a fresh pairing code, the plugin automatically configures:
118
+
119
+ ```json
120
+ {
121
+ "groupPolicy": "open",
122
+ "groups": {
123
+ "*": {
124
+ "autoReply": true,
125
+ "enabled": true
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ This means:
132
+ - Bot joins any room it's invited to
133
+ - Bot responds to all messages (no @mention required)
134
+ - Bot uses **your OpenClaw workspace personality** (SOUL.md, IDENTITY.md, etc.) in all conversations — groups and DMs alike
135
+
136
+ When the bot joins a new encrypted room, it sends a hint message explaining the `/bot talk on|off` commands so room members know how to control it.
137
+
138
+ ### Your Personality, Everywhere
139
+
140
+ BadgerClaw respects your OpenClaw workspace files. If you've configured a custom personality (SOUL.md), the bot uses that personality in groups and DMs. This means:
141
+
142
+ - A "pirate assistant" SOUL.md → bot talks like a pirate in groups
143
+ - A "professional COO" SOUL.md → bot acts professional in groups
144
+ - No SOUL.md → bot uses the default helpful assistant behavior
145
+
146
+ **If your bot stays silent in groups**, your workspace files may include instructions like "stay silent in groups" or "only respond when needed." To fix this:
147
+
148
+ 1. Edit your SOUL.md to allow group responses, OR
149
+ 2. Add a group-specific system prompt override:
150
+
151
+ ```json
152
+ {
153
+ "channels": {
154
+ "badgerclaw": {
155
+ "groups": {
156
+ "*": {
157
+ "autoReply": true,
158
+ "systemPrompt": "You are a helpful AI assistant. Always respond to messages in group chats."
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### Per-Room Configuration
167
+
168
+ You can configure specific rooms differently:
169
+
170
+ ```json
171
+ {
172
+ "channels": {
173
+ "badgerclaw": {
174
+ "groups": {
175
+ "*": { "autoReply": true },
176
+ "!specificRoomId:server": {
177
+ "autoReply": false,
178
+ "systemPrompt": "Custom prompt for this room only"
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Upgrading from v1.1.x or Earlier
189
+
190
+ If you installed BadgerClaw before v1.2.0, your config is missing the group auto-reply settings. The bot may not respond in group chats without @mentions.
191
+
192
+ **Quick fix — run the update command:**
193
+
194
+ ```bash
195
+ openclaw plugins update @badgerclaw/connect
196
+ openclaw configure
197
+ ```
198
+
199
+ Select BadgerClaw and re-enter a pairing code. The new onboarding will add the missing group config automatically.
200
+
201
+ **Manual fix — if you don't want to re-pair:**
202
+
203
+ Add this to your `~/.openclaw/openclaw.json` inside `channels.badgerclaw`:
204
+
205
+ ```json
206
+ {
207
+ "channels": {
208
+ "badgerclaw": {
209
+ "groupPolicy": "open",
210
+ "groups": {
211
+ "*": {
212
+ "autoReply": true,
213
+ "enabled": true
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ ```
220
+
221
+ Then restart: `openclaw gateway restart`
222
+
223
+ ---
224
+
225
+ ## FAQ
226
+
227
+ ### Bot doesn't respond in group chats
228
+
229
+ 1. Send `/bot talk on` in the room to enable auto-reply
230
+ 2. Make sure the bot is a member of the room (`/bot add <name>`)
231
+ 3. Check OpenClaw is running: `openclaw status`
232
+
233
+ ### Bot shows typing indicator but never replies
234
+
235
+ Your workspace personality (SOUL.md) may tell the agent to stay silent in groups. BadgerClaw respects your workspace files, so if SOUL.md says "don't respond in groups," the bot won't.
236
+
237
+ **Fix options:**
238
+ 1. Edit your SOUL.md to allow group responses
239
+ 2. Add a `systemPrompt` override in `channels.badgerclaw.groups.*` that tells the agent to respond (see Group Chat Configuration above)
240
+ 3. Run `openclaw configure` and reconfigure BadgerClaw
241
+
242
+ ### `/bot talk on` doesn't work
243
+
244
+ After changing bot commands, you may need to restart the gateway:
245
+
246
+ ```bash
247
+ openclaw gateway restart
248
+ ```
249
+
250
+ ### Bot responds with wrong personality
251
+
252
+ The bot uses your **OpenClaw workspace personality** (SOUL.md, IDENTITY.md) for both DMs and groups. To set a different personality for groups only, add a `systemPrompt` in `channels.badgerclaw.groups.*` in your config.
253
+
254
+ ### Bot keeps saying "NO_REPLY" or stays silent
255
+
256
+ Your workspace files (SOUL.md) instruct the agent to stay silent in groups. BadgerClaw respects your personality — this is intentional.
257
+
258
+ **To fix:** Add a `systemPrompt` override to your groups config that tells the agent to always respond. See the "Your Personality, Everywhere" section above. Then restart: `openclaw gateway restart`
95
259
 
96
260
  ### "Invalid pairing code"
97
- - Code may have expired (24h limit). Run `/bot pair <name>` in the app to get a new one.
98
- - Make sure you're entering the code exactly as shown (BCK-XXXX-XXXX).
99
261
 
100
- ### Bot doesn't respond
101
- 1. Check OpenClaw is running: `openclaw status`
102
- 2. Check gateway logs: `openclaw logs --follow`
103
- 3. Verify the BadgerClaw channel is configured: `openclaw channels status`
262
+ - Code expires after 24 hours. Run `/bot pair <name>` in the app for a new one.
263
+ - Enter the code exactly as shown (BCK-XXXX-XXXX).
104
264
 
105
265
  ### "Pairing code already redeemed"
106
- Each code is one-time use. Run `/bot pair <name>` to generate a fresh one.
107
266
 
108
- ### Need to reconnect
109
- Run `openclaw configure` again and enter a new pairing code.
267
+ Each code is one-time use. Run `/bot pair <name>` to generate a fresh one.
110
268
 
111
269
  ---
112
270
 
@@ -115,9 +273,9 @@ Run `openclaw configure` again and enter a new pairing code.
115
273
  ```
116
274
  Your Phone (BadgerClaw App)
117
275
 
118
- │ E2EE Messages
276
+ │ E2EE Messages (Megolm/Olm)
119
277
 
120
- BadgerClaw Server (badger.signout.io)
278
+ BadgerClaw Server (Matrix homeserver)
121
279
 
122
280
  │ E2EE Messages
123
281
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@badgerclaw/connect",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "BadgerClaw channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -31,4 +31,4 @@
31
31
  "defaultChoice": "npm"
32
32
  }
33
33
  }
34
- }
34
+ }
@@ -31,13 +31,44 @@ function resolveMatrixRoomConfigForGroup(params: ChannelGroupContext) {
31
31
  export function resolveMatrixGroupRequireMention(params: ChannelGroupContext): boolean {
32
32
  // Check per-room config first (set by /bot talk on|off)
33
33
  try {
34
- const { getRoomAutoReply } = require("./matrix/monitor/bot-commands.js");
35
- const roomId = params.groupId?.trim() ?? "";
36
- const roomAutoReply = getRoomAutoReply(roomId);
37
- if (roomAutoReply === true) return false;
38
- if (roomAutoReply === false) return true;
39
- } catch {
40
- // bot-commands module not available, fall through
34
+ const fs = require("fs");
35
+ const path = require("path");
36
+ const configPath = path.join(
37
+ process.env.HOME || "/tmp",
38
+ ".openclaw/extensions/badgerclaw/room-config.json"
39
+ );
40
+ const raw = fs.readFileSync(configPath, "utf-8");
41
+ const roomConfig = JSON.parse(raw) as Record<string, { autoReply?: boolean }>;
42
+ const rawGroupId = params.groupId?.trim() ?? "";
43
+ // Try multiple formats: raw, stripped prefixes, just the room ID part
44
+ const variants = [
45
+ rawGroupId,
46
+ rawGroupId.replace(/^badgerclaw:/, ""),
47
+ rawGroupId.replace(/^channel:/, ""),
48
+ rawGroupId.replace(/^room:/, ""),
49
+ ];
50
+ // Case-insensitive lookup: OpenClaw may lowercase the groupId while
51
+ // room-config.json stores original-cased Matrix room IDs
52
+ const configKeys = Object.keys(roomConfig);
53
+ for (const variant of variants) {
54
+ if (!variant) continue;
55
+ const matchedKey = configKeys.find(
56
+ (k) => k.toLowerCase() === variant.toLowerCase()
57
+ );
58
+ if (matchedKey) {
59
+ if (roomConfig[matchedKey]?.autoReply === true) {
60
+ console.log(`[badgerclaw] room-config autoReply=true for ${matchedKey} (lookup=${variant})`);
61
+ return false;
62
+ }
63
+ if (roomConfig[matchedKey]?.autoReply === false) {
64
+ console.log(`[badgerclaw] room-config autoReply=false for ${matchedKey} (lookup=${variant})`);
65
+ return true;
66
+ }
67
+ }
68
+ }
69
+ console.log(`[badgerclaw] room-config: no match for groupId="${rawGroupId}", keys=${configKeys.join(",")}`);
70
+ } catch (err) {
71
+ console.log(`[badgerclaw] room-config error: ${err}`);
41
72
  }
42
73
 
43
74
  const resolved = resolveMatrixRoomConfigForGroup(params);
@@ -34,11 +34,47 @@ export function registerMatrixAutoJoin(params: {
34
34
  }
35
35
  autoJoinRegistered.add(client);
36
36
 
37
+ // After joining a room, send a notice in encrypted rooms to force Megolm session rotation.
38
+ // When the bot joins, other clients may use a cached outbound Megolm session that doesn't
39
+ // include the bot. Sending a message causes compliant clients to detect the new member and
40
+ // rotate their session so subsequent messages are decryptable by the bot.
41
+ async function postJoinEncryptionHandshake(roomId: string) {
42
+ try {
43
+ const encryptionState = await client
44
+ .getRoomStateEvent(roomId, "m.room.encryption", "")
45
+ .catch(() => null);
46
+
47
+ if (!encryptionState) {
48
+ logVerbose(`badgerclaw: room ${roomId} is not encrypted, skipping handshake`);
49
+ return;
50
+ }
51
+
52
+ logVerbose(`badgerclaw: room ${roomId} is encrypted, sending notice to trigger key rotation`);
53
+ await client.sendNotice(
54
+ roomId,
55
+ "🔐 Connected — encryption active.\n\n" +
56
+ "I'll respond when @mentioned. To toggle auto-reply:\n" +
57
+ "• /bot talk on — I'll respond to every message\n" +
58
+ "• /bot talk off — I'll only respond when @mentioned\n" +
59
+ "• /bot help — see all commands",
60
+ );
61
+ logVerbose(`badgerclaw: sent encryption handshake + hint notice in room ${roomId}`);
62
+ } catch (err) {
63
+ runtime.log?.(`badgerclaw: encryption handshake failed for room ${roomId}: ${String(err)}`);
64
+ }
65
+ }
66
+
37
67
  if (autoJoin === "always") {
38
68
  // Use the built-in autojoin mixin for "always" mode
39
69
  const { AutojoinRoomsMixin } = loadMatrixSdk();
40
70
  AutojoinRoomsMixin.setupOnClient(client);
41
71
  logVerbose("badgerclaw: auto-join enabled for all invites");
72
+
73
+ // AutojoinRoomsMixin handles the join, so listen for room.join to run post-join logic
74
+ client.on("room.join", async (roomId: string, _joinEvent: unknown) => {
75
+ logVerbose(`badgerclaw: bot joined room ${roomId} (always mode), running post-join handshake`);
76
+ await postJoinEncryptionHandshake(roomId);
77
+ });
42
78
  return;
43
79
  }
44
80
 
@@ -75,6 +111,7 @@ export function registerMatrixAutoJoin(params: {
75
111
  try {
76
112
  await client.joinRoom(roomId);
77
113
  logVerbose(`badgerclaw: joined room ${roomId}`);
114
+ await postJoinEncryptionHandshake(roomId);
78
115
  } catch (err) {
79
116
  runtime.error?.(`badgerclaw: failed to join room ${roomId}: ${String(err)}`);
80
117
  }
@@ -7,6 +7,12 @@ const ROOM_CONFIG_PATH = path.join(
7
7
  ".openclaw/extensions/badgerclaw/room-config.json"
8
8
  );
9
9
 
10
+ // Session store path for core groupActivation
11
+ const SESSION_STORE_PATH = path.join(
12
+ process.env.HOME || "/tmp",
13
+ ".openclaw/agents/main/sessions/sessions.json"
14
+ );
15
+
10
16
  function loadRoomConfig(): Record<string, { autoReply?: boolean }> {
11
17
  try {
12
18
  return JSON.parse(fs.readFileSync(ROOM_CONFIG_PATH, "utf-8"));
@@ -19,6 +25,22 @@ function saveRoomConfig(config: Record<string, { autoReply?: boolean }>): void {
19
25
  fs.writeFileSync(ROOM_CONFIG_PATH, JSON.stringify(config, null, 2));
20
26
  }
21
27
 
28
+ function setGroupActivation(roomId: string, activation: "always" | "mention"): void {
29
+ try {
30
+ const store = JSON.parse(fs.readFileSync(SESSION_STORE_PATH, "utf-8"));
31
+ // Session key format: agent:main:badgerclaw:channel:!roomid (lowercase)
32
+ const sessionKey = `agent:main:badgerclaw:channel:${roomId.toLowerCase()}`;
33
+ if (!store[sessionKey]) {
34
+ store[sessionKey] = {};
35
+ }
36
+ store[sessionKey].groupActivation = activation;
37
+ fs.writeFileSync(SESSION_STORE_PATH, JSON.stringify(store, null, 2));
38
+ console.log(`[badgerclaw] set groupActivation=${activation} for ${sessionKey}`);
39
+ } catch (err) {
40
+ console.error(`[badgerclaw] failed to set groupActivation: ${err}`);
41
+ }
42
+ }
43
+
22
44
  export function getRoomAutoReply(roomId: string): boolean | undefined {
23
45
  const config = loadRoomConfig();
24
46
  return config[roomId]?.autoReply;
@@ -106,8 +128,11 @@ export async function handleBotCommand(params: {
106
128
  case "talk": {
107
129
  if (arg === "on") {
108
130
  const config = loadRoomConfig();
109
- config[roomId] = { ...config[roomId], autoReply: true };
131
+ // Store with lowercase key to match OpenClaw's lowercased groupId
132
+ const normalizedRoomId = roomId.toLowerCase();
133
+ config[normalizedRoomId] = { ...config[normalizedRoomId], autoReply: true };
110
134
  saveRoomConfig(config);
135
+ setGroupActivation(roomId, "always");
111
136
  await client.sendMessage(roomId, {
112
137
  msgtype: "m.text",
113
138
  body: "✅ Auto-reply enabled — I'll respond to every message in this room.",
@@ -116,8 +141,10 @@ export async function handleBotCommand(params: {
116
141
  }
117
142
  if (arg === "off") {
118
143
  const config = loadRoomConfig();
119
- config[roomId] = { ...config[roomId], autoReply: false };
144
+ const normalizedRoomId = roomId.toLowerCase();
145
+ config[normalizedRoomId] = { ...config[normalizedRoomId], autoReply: false };
120
146
  saveRoomConfig(config);
147
+ setGroupActivation(roomId, "mention");
121
148
  await client.sendMessage(roomId, {
122
149
  msgtype: "m.text",
123
150
  body: "✅ Auto-reply disabled — I'll only respond when @mentioned.",
@@ -472,14 +472,39 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
472
472
  });
473
473
  return;
474
474
  }
475
+ // Check room-config.json first (set by /bot talk on|off) — it takes priority
476
+ // over the OpenClaw config wildcard entry.
477
+ const roomConfigJsonAutoReply = (() => {
478
+ try {
479
+ const fs = require("fs");
480
+ const path = require("path");
481
+ const configPath = path.join(
482
+ process.env.HOME || "/tmp",
483
+ ".openclaw/extensions/badgerclaw/room-config.json"
484
+ );
485
+ const raw = fs.readFileSync(configPath, "utf-8");
486
+ const roomCfg = JSON.parse(raw) as Record<string, { autoReply?: boolean }>;
487
+ const normalizedRoomId = roomId.toLowerCase();
488
+ const keys = Object.keys(roomCfg);
489
+ const matchedKey = keys.find((k) => k.toLowerCase() === normalizedRoomId);
490
+ if (matchedKey && typeof roomCfg[matchedKey]?.autoReply === "boolean") {
491
+ return roomCfg[matchedKey].autoReply;
492
+ }
493
+ } catch { /* ignore */ }
494
+ return undefined;
495
+ })();
475
496
  const shouldRequireMention = isRoom
476
- ? roomConfig?.autoReply === true
497
+ ? roomConfigJsonAutoReply === true
477
498
  ? false
478
- : roomConfig?.autoReply === false
499
+ : roomConfigJsonAutoReply === false
479
500
  ? true
480
- : typeof roomConfig?.requireMention === "boolean"
481
- ? roomConfig?.requireMention
482
- : true
501
+ : roomConfig?.autoReply === true
502
+ ? false
503
+ : roomConfig?.autoReply === false
504
+ ? true
505
+ : typeof roomConfig?.requireMention === "boolean"
506
+ ? roomConfig?.requireMention
507
+ : true
483
508
  : false;
484
509
  const shouldBypassMention =
485
510
  allowTextCommands &&
package/src/onboarding.ts CHANGED
@@ -245,6 +245,16 @@ export const badgerclawOnboardingAdapter: ChannelOnboardingAdapter = {
245
245
  autoJoin: "always",
246
246
  // Open policy: bot responds in any room it's invited to
247
247
  groupPolicy: "open",
248
+ // Default group config: auto-reply in all rooms.
249
+ // No systemPrompt override — the bot respects the user's workspace personality
250
+ // (SOUL.md, IDENTITY.md, etc.). When the bot joins a group, it sends a hint
251
+ // message about /bot talk on|off so users know how to control it.
252
+ groups: {
253
+ "*": {
254
+ autoReply: true,
255
+ enabled: true,
256
+ },
257
+ },
248
258
  dm: {
249
259
  ...next.channels?.badgerclaw?.dm,
250
260
  policy: "open",