Skip to content

Instantly share code, notes, and snippets.

@thanakijwanavit
Created March 4, 2026 03:04
Show Gist options
  • Select an option

  • Save thanakijwanavit/726bb492a0f84434a460d57f1456781f to your computer and use it in GitHub Desktop.

Select an option

Save thanakijwanavit/726bb492a0f84434a460d57f1456781f to your computer and use it in GitHub Desktop.
Gasclaw Smart Coordinator: single-bot multi-agent Telegram routing for OpenClaw teams

Gasclaw Smart Coordinator Setup

Single-bot, multi-agent Telegram routing for OpenClaw teams. All messages go to one coordinator who delegates to specialists via per-topic systemPrompt.

Why

OpenClaw doesn't support per-topic bindings (threadId in match.peer is rejected). Creating 10 BotFather bots is overkill. Instead: one bot, one binding, smart routing via systemPrompts.

User writes in "DevOps" topic
  → Coordinator receives message
  → systemPrompt says: "Delegate to agent 'devops' using sessions_send"
  → Coordinator calls sessions_send(agentId="devops", message=...)
  → DevOps agent works in its own workspace
  → DevOps agent posts results back to topic 466 via sendMessage tool

Quick Start

pip install gasclaw
from pathlib import Path
from gasclaw.openclaw.team_config import (
    AgentSpec, generate_team_config, write_team_workspaces, build_topic_routes
)

# Define your team
agents = [
    AgentSpec(
        id="coordinator", name="Tech Lead", emoji="🧑‍💻",
        is_coordinator=True,
        tools_allow=["exec", "read", "write", "sessions_send", "sessions_spawn"],
    ),
    AgentSpec(
        id="devops", name="DevOps Engineer", emoji="🚀",
        system_prompt="You handle CI/CD, Docker, and infrastructure.",
        tools_allow=["exec", "read", "write", "edit"],
    ),
    AgentSpec(
        id="backend-dev", name="Backend Developer", emoji="🔨",
        system_prompt="You write code and implement features.",
        tools_allow=["exec", "read", "write", "edit", "apply_patch"],
    ),
    AgentSpec(
        id="doctor", name="Doctor", emoji="🏥",
        system_prompt="You monitor system health and fix issues.",
        tools_allow=["exec", "read"],
    ),
]

# Map agents to Telegram forum topic IDs (create topics first via BotFather or API)
topic_map = {
    "coordinator": "462",
    "devops": "466",
    "backend-dev": "464",
    "doctor": "477",
}

# Generate openclaw.json
config = generate_team_config(
    agents, topic_map,
    bot_token="YOUR_BOT_TOKEN",
    chat_id="-100YOUR_GROUP_ID",
    owner_id="YOUR_TELEGRAM_USER_ID",
    kimi_key="sk-your-key",
    auth_token="random-hex-token",
    openclaw_base=Path("~/.openclaw").expanduser(),
)

# Write it
import json
Path("~/.openclaw/openclaw.json").expanduser().write_text(json.dumps(config, indent=2))

# Create workspaces with SOUL.md and optional knowledge docs
write_team_workspaces(
    agents, topic_map,
    chat_id="-100YOUR_GROUP_ID",
    openclaw_base=Path("~/.openclaw").expanduser(),
    knowledge_dir=Path("/opt/knowledge"),  # optional
)

From a YAML Preset

# presets/backend.yaml
name: backend
description: Backend software development team
coordination: hierarchical

coordinator:
  id: coordinator
  name: Tech Lead
  emoji: "🧑‍💻"
  tools:
    allow: [exec, read, write, sessions_list, sessions_send, sessions_spawn]

agents:
  - id: devops
    name: DevOps Engineer
    emoji: "🚀"
    system_prompt: "You handle CI/CD and infrastructure."
    tools:
      allow: [exec, read, write, edit]
  - id: backend-dev
    name: Backend Developer
    emoji: "🔨"
    system_prompt: "You write code."
    tools:
      allow: [exec, read, write, edit, apply_patch]
from gasclaw.openclaw.team_config import load_preset_agents, generate_team_config

agents = load_preset_agents(Path("presets/backend.yaml"))
config = generate_team_config(agents, topic_map, ...)

What Gets Generated

openclaw.json (key parts)

{
  "bindings": [
    {"agentId": "coordinator", "match": {"channel": "telegram"}}
  ],
  "channels": {
    "telegram": {
      "network": {"autoSelectFamily": false},
      "actions": {"sendMessage": true},
      "groups": {
        "-100YOUR_GROUP_ID": {
          "groupPolicy": "open",
          "topics": {
            "1":   {"requireMention": false},
            "462": {"requireMention": false, "systemPrompt": "You are in the Tech Lead topic. This is YOUR topic. Handle coordination directly."},
            "466": {"requireMention": false, "systemPrompt": "This is the DevOps Engineer topic. Delegate to agent \"devops\" using the sessions_send tool."},
            "464": {"requireMention": false, "systemPrompt": "This is the Backend Developer topic. Delegate to agent \"backend-dev\" using the sessions_send tool."},
            "477": {"requireMention": false, "systemPrompt": "This is the Doctor topic. Delegate to agent \"doctor\" using the sessions_send tool."}
          }
        }
      }
    }
  },
  "tools": {
    "agentToAgent": {"enabled": true, "allow": ["coordinator", "devops", "backend-dev", "doctor"]}
  }
}

Coordinator SOUL.md (auto-generated)

The coordinator gets a delegation table:

| Specialist (name / id) | Topic | Delegate via |
|------------------------|-------|--------------|
| DevOps Engineer (devops) | 466 | `sessions_send` |
| Backend Developer (backend-dev) | 464 | `sessions_send` |
| Doctor (doctor) | 477 | `sessions_send` |

Plus instructions that sessions_send is a tool call (not a shell command).

Knowledge Distribution

If you provide a knowledge_dir, every agent gets a knowledge/ folder with condensed docs:

~/.openclaw/workspace-devops/knowledge/
├── openclaw-reference.md
├── gastown-reference.md
├── ais-reference.md
├── gasclaw-architecture.md
└── beads-reference.md

Critical Config Details

General topic MUST stay enabled

"1": {"requireMention": false}

Never set "enabled": false on topic 1 — it silently drops all inbound messages in forum groups because that's where users type by default.

IPv4-only Telegram polling

"network": {"autoSelectFamily": false}

Prevents IPv6 fallback issues that cause intermittent fetch fallback warnings and dropped connections in containers.

sendMessage action required

"actions": {"sendMessage": true}

Without this, agents can't post to specific topics via the sendMessage tool.

Single binding (no threadId)

"bindings": [{"agentId": "coordinator", "match": {"channel": "telegram"}}]

OpenClaw rejects peer.threadId in bindings. Don't try it — it causes Invalid config: Unrecognized key "threadId" and breaks the gateway.

Creating Telegram Topics Programmatically

import urllib.request, json

def create_topic(bot_token, chat_id, name):
    url = f"https://api.telegram.org/bot{bot_token}/createForumTopic"
    data = json.dumps({"chat_id": chat_id, "name": name}).encode()
    req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
    with urllib.request.urlopen(req) as resp:
        return json.loads(resp.read())["result"]["message_thread_id"]

# Create topics for each agent
topic_map = {}
for agent in agents:
    topic_map[agent.id] = str(create_topic(TOKEN, CHAT_ID, f"{agent.emoji} {agent.name}"))

Beads Memory (per-agent)

Each agent gets its own Git-backed beads database:

for agent_id in coordinator devops backend-dev doctor; do
    BD_DIR="/workspace/beads/$agent_id"
    mkdir -p "$BD_DIR" && cd "$BD_DIR"
    git init --initial-branch=main
    git config user.email "${agent_id}@gasclaw.local"
    mkdir -p .beads
    echo '{"version":1,"agent":"'$agent_id'"}' > .beads/config.json
    git add . && git commit -m "init beads for $agent_id"
done

Agents use BD_ROOT=/workspace/beads/<agent-id> bd new "title" --body "details" to log findings.

Full Example: Docker Entrypoint

# In entrypoint.sh after starting the gateway:
python3 -c "
from pathlib import Path
from gasclaw.openclaw.team_config import load_preset_agents, generate_team_config, write_team_workspaces

agents = load_preset_agents(Path('/opt/presets/backend.yaml'))
topic_map = {}  # load from team-topics.json or create via API
config = generate_team_config(agents, topic_map, bot_token='...', ...)
Path('~/.openclaw/openclaw.json').expanduser().write_text(
    __import__('json').dumps(config, indent=2)
)
write_team_workspaces(agents, topic_map, '-100...', Path('~/.openclaw').expanduser(),
                      knowledge_dir=Path('/opt/knowledge'))
"
openclaw gateway run

Links

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment