Zero code changes. Config only. Works with any OpenClaw bot.
Adding your OpenClaw bot to a new Telegram group used to require:
- Create the group
- Add the bot
- Find the chat ID somehow
- Manually write a
systemPrompt - Edit
openclaw.json, add the group entry - Restart the gateway
That's 6 steps with context switches between Telegram and your terminal. Annoying.
Create group → add bot → /setup → answer one question → done. The bot configures itself.
flowchart TD
A["Create group<br>in Telegram"] --> B["Add bot<br>as member"]
B --> C["Tap /setup<br>from menu"]
C --> D["Bot asks context"]
D --> E["User answers"]
E --> F["Bot runs config.patch<br>systemPrompt + settings"]
F --> G["✅ Group is live"]
The wildcard entry "*" in the config catches any unknown group. Its systemPrompt is a bootstrap script that teaches the agent how to handle /setup. Once setup completes, the bot writes a permanent group-specific entry that replaces the wildcard for that chat ID.
Add these settings to your openclaw.json (or use gateway config.patch):
{
"channels": {
"telegram": {
"enabled": true,
"groupPolicy": "allowlist",
"groupAllowFrom": ["+1234567890"],
"customCommands": [
{
"command": "setup",
"description": "Configure this group for the bot"
}
],
"groups": {
"*": {
"requireMention": false,
"systemPrompt": "<bootstrap prompt — see below>"
}
}
}
}
}Key settings explained:
| Setting | Value | Why |
|---|---|---|
groupPolicy |
"allowlist" |
Only phone numbers in groupAllowFrom can trigger the bot. Security gate. |
groupAllowFrom |
["+1234567890"] |
Your phone number(s). The bot ignores messages from anyone else. |
groups."*" |
{...} |
Wildcard — matches ANY group the bot is added to. |
requireMention |
false |
Critical. The user's reply to "what's the context?" won't have an @mention. If true, the bot never sees it. |
customCommands |
[{setup}] |
Registers /setup with OpenClaw's command router and with Telegram's menu (via setMyCommands at startup). |
OpenClaw automatically calls Telegram's setMyCommands on startup, merging its native commands (/new, /status, /model, etc.), skill commands, and your customCommands. You never need to call setMyCommands manually.
This is the systemPrompt for the "*" wildcard entry. It's what teaches the agent to handle /setup:
## New Group — Auto-Setup Handler
You are in a new unconfigured Telegram group. Your ONLY job right now is to handle /setup.
### When you see /setup (or /setup@yourbotusername):
1. Ask: "What is this group about?"
2. Wait for the user's answer.
3. Once you have the context, do ONE config.patch that includes BOTH:
- requireMention: false
- a systemPrompt tailored to the group context
4. Extract the chat ID from your session key (the number after 'group:')
5. Apply via gateway config.patch:
{"channels":{"telegram":{"groups":{"<chatId>":{"requireMention":false,"systemPrompt":"<generated>"}}}}}
6. Confirm to the user with the chat ID and a summary.
### Before /setup is run:
If someone writes anything other than /setup, respond:
"This group isn't configured yet. Tap /setup to get started."
### IMPORTANT:
- Do NOT patch requireMention alone first — do everything in ONE patch
(a restart between patches would lose the session context)
- The systemPrompt you generate will REPLACE this bootstrap prompt permanently
- Generate prompts in the same style: topic header, what the group is for,
relevant paths/skills, behavioral rules
OpenClaw has two independent gates for Telegram groups:
flowchart TD
A["Message arrives"] --> B{"Gate 1: groups section<br>Which GROUPS are allowed?"}
B -->|"'*' = all groups"| C{"Gate 2: groupPolicy<br>Which SENDERS are allowed?"}
B -->|"Unknown group, no '*'"| X["❌ Rejected"]
C -->|"Phone in groupAllowFrom"| D["✅ Bot processes message"]
C -->|"Unknown sender"| Y["❌ Rejected"]
Both must pass. The wildcard "*" opens Gate 1 to all groups, while groupPolicy: "allowlist" keeps Gate 2 locked to your authorized numbers. This is the right security tradeoff — any group is fine, but only you can talk to the bot.
There's a subtle issue with requireMention:
- User taps
/setup→ bot receives it (commands always go through) - Bot asks "What's the context?"
- User types "Project X development" (no @mention)
- If
requireMention: trueon wildcard → message silently dropped 💀
The fix: set requireMention: false on the "*" wildcard. This is safe because groupPolicy: "allowlist" already prevents randos from triggering the bot.
You might think: first patch requireMention, then patch systemPrompt after getting context. Don't.
config.patch triggers a gateway restart. The restart kills the session. When the session resumes, it loads the wildcard bootstrap prompt again — but the user's context answer is gone. The bot asks again. Infinite loop.
Solution: Wait until you have everything, then do ONE patch with both requireMention: false and the final systemPrompt.
1. User creates "Project X Dev" group in Telegram
2. User adds @yourbotusername to the group
3. User taps the "/" menu → "setup"
4. Bot (using wildcard "*" prompt): "What's this group about?"
5. User: "Project X development — React frontend, Python backend"
6. Bot generates a systemPrompt, runs:
gateway config.patch {
"channels": {
"telegram": {
"groups": {
"-501234567": {
"requireMention": false,
"systemPrompt": "## Project X Dev — Development...\n\n..."
}
}
}
}
}
7. Gateway restarts with the new permanent entry
8. Bot confirms: "✅ Group configured (chat ID: -501234567)"
9. Next message in this group uses the new systemPrompt
For a fresh OpenClaw bot that only needs Telegram group provisioning:
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "YOUR_BOT_TOKEN",
"dmPolicy": "allowlist",
"allowFrom": ["+1234567890"],
"groupPolicy": "allowlist",
"groupAllowFrom": ["+1234567890"],
"customCommands": [
{
"command": "setup",
"description": "Configure this group"
}
],
"groups": {
"*": {
"requireMention": false,
"systemPrompt": "## New Group — Auto-Setup Handler\n\nYou are in a new unconfigured Telegram group. Your ONLY job is to handle /setup.\n\n### When you see /setup:\n1. Ask: \"What is this group about?\"\n2. Wait for the answer.\n3. Generate a systemPrompt tailored to the context.\n4. Extract chat ID from your session key (number after 'group:').\n5. Apply ONE config.patch: {\"channels\":{\"telegram\":{\"groups\":{\"<chatId>\":{\"requireMention\":false,\"systemPrompt\":\"<generated>\"}}}}}.\n6. Confirm to user.\n\n### Before /setup:\nRespond: \"This group isn't configured yet. Tap /setup to start.\"\n\n### Rules:\n- ONE patch only (restart between patches loses context)\n- Generated prompt replaces this bootstrap permanently"
}
}
}
},
"plugins": {
"entries": {
"telegram": {
"enabled": true
}
}
}
}-
The wildcard stays forever — After setup, the
"*"entry still exists. New groups still get the bootstrap flow. That's the point. Don't remove it. -
groupPolicy: "allowlist"checks phone numbers — The user must have a phone number linked to their Telegram account that matchesgroupAllowFrom. Telegram user IDs alone won't work here. -
No
my_chat_membersupport (yet) — Ideally the bot would detect being added to a group and auto-ask for context. OpenClaw doesn't expose Telegram'smy_chat_memberevents yet, so/setupis the workaround.
Copy-paste this into your openclaw.json under channels.telegram and restart. That's it.
{
"customCommands": [
{
"command": "setup",
"description": "Configure this group"
}
],
"groupPolicy": "allowlist",
"groupAllowFrom": ["+YOUR_PHONE_NUMBER"],
"groups": {
"*": {
"requireMention": false,
"systemPrompt": "## New Group — Auto-Setup Handler\n\nYou are in a new unconfigured Telegram group. Your ONLY job right now is to handle /setup.\n\n### When you see /setup:\n\n1. Ask: \"What is this group about?\"\n2. Wait for the user's answer.\n3. Once you have the context, do ONE gateway config.patch that includes BOTH requireMention and systemPrompt:\n - Extract the chat ID from your session key (the number after 'group:')\n - Generate a systemPrompt tailored to the group context (topic header, what this group is for, relevant skills/data paths, behavioral rules)\n - Apply: gateway config.patch with {\"channels\":{\"telegram\":{\"groups\":{\"<chatId>\":{\"requireMention\":false,\"systemPrompt\":\"<your generated prompt>\"}}}}}\n4. Confirm to the user with the chat ID and a summary of the generated prompt.\n\n### Before /setup is run:\nIf someone writes anything other than /setup, respond: \"This group isn't configured yet. Tap /setup to get started.\"\n\n### Rules:\n- Do everything in ONE config.patch (a gateway restart between patches loses session context)\n- The systemPrompt you generate will permanently replace this bootstrap prompt for this group\n- Never patch requireMention separately from systemPrompt"
}
}
}Replace +YOUR_PHONE_NUMBER with your actual number. Create a group, add the bot, tap /setup, answer one question. Done.
Do whatever you want with this. It's config, not code.
Thanks a lot! This is honestly a great idea. Especcialy in case when some OpenClaw plugins doesn't support Telegram topics:
It can be only one option to avoid manual config edition. Thanks!