How to Configure the Multi-Channel IM Bot Gateway (QQ, Feishu, WeChat) with Routes and Allowlist

Configure the multi-channel IM bot gateway in DeepSeek-Reasonix by defining a global [bot.allowlist] for access control and granular [[bot.routes]] to route QQ, Feishu, and WeChat messages to specific workspaces, models, and tool-approval modes.

The esengine/DeepSeek-Reasonix repository provides a single shared Go gateway that handles multiple IM bots simultaneously. Two configuration layers in the TOML file control access and message routing: the allowlist acts as a global gatekeeper, while routes provide fine-grained overrides per connection, chat, or user.

Architecture Overview

The gateway reads the Bot section from the global Reasonix configuration (internal/config/config.go). The BotConfig struct defines the relationship between connections, allowlists, and routes:

// BotConfig – controls the multi‑channel IM bot gateway.
// (source: internal/config/config.go#L34-L53)
type BotConfig struct {
    Enabled            bool   `toml:"enabled"`
    Model              string `toml:"model"`
    ToolApprovalMode   string `toml:"tool_approval_mode"`
    Allowlist          BotAllowlist          `toml:"allowlist"`   // global access control
    Routes             []BotRouteConfig      `toml:"routes"`      // per-message routing
    Connections        []BotConnectionConfig `toml:"connections"` // individual connections
}

When a message arrives, the gateway performs two sequential checks:

  1. Allowlist validation (internal/gateway/gateway.go#L1046) – Validates if the sender is authorized to interact with the bot.
  2. Route evaluation – Iterates through [[bot.routes]] and applies the first-match-wins rule to determine the effective model, workspace, and approval mode.

Global Allowlist ([bot.allowlist])

The BotAllowlist struct (internal/config/config.go#L94-L104) provides a fallback access control layer for connections without explicit per-connection access rules:

type BotAllowlist struct {
    Enabled      bool     `toml:"enabled"`
    AllowAll     bool     `toml:"allow_all"`
    QQUsers      []string `toml:"qq_users"`
    FeishuUsers  []string `toml:"feishu_users"`
    WeixinUsers  []string `toml:"weixin_users"`
    QQAdmins     []string `toml:"qq_admins"`
    FeishuAdmins []string `toml:"feishu_admins"`
    // ...
}

When allow_all is set to false, the gateway checks the sender against the listed users, groups, and admins before consulting any routes.

Message Routes ([[bot.routes]])

Routes are defined by the BotRouteConfig struct (internal/config/config.go#L82-L92):

type BotRouteConfig struct {
    ConnectionID     string `toml:"connection_id"`
    Platform         string `toml:"platform"`  // qq | feishu | weixin
    ChatType         string `toml:"chat_type"` // dm | group
    ChatID           string `toml:"chat_id"`
    UserID           string `toml:"user_id"`
    ThreadID         string `toml:"thread_id"`
    Model            string `toml:"model"`
    ToolApprovalMode string `toml:"tool_approval_mode"`
    WorkspaceRoot    string `toml:"workspace_root"`
}

Empty fields act as wildcards. The runtime converts these configurations in internal/botruntime/runtime.go#L58-L86 into active routing rules used by the gateway.

Practical Configuration Examples

Deny-by-Default with Feishu and QQ

This configuration enables the gateway with a restrictive allowlist and specific routes for different platforms:

[bot]
enabled = true
model = "deepseek-coder-v2"
tool_approval_mode = "ask"

# Global allowlist – deny by default, allow specific users

[bot.allowlist]
enabled = true
allow_all = false
feishu_users = ["ou_12345"]      # Feishu user IDs

qq_admins = ["12345678"]         # QQ admin QQ numbers

# Route: QQ group messages to dedicated workspace

[[bot.routes]]
connection_id = "qq-main"
platform = "qq"
chat_type = "group"
chat_id = "1234567890"
workspace_root = "/projects/qq-group"
model = "deepseek-coder-v2"
tool_approval_mode = "auto"

# Route: Feishu DM from power-user to high-capacity model

[[bot.routes]]
connection_id = "feishu-main"
platform = "feishu"
chat_type = "dm"
user_id = "ou_99999"
model = "deepseek-coder-v2-max"
tool_approval_mode = "yolo"

# Connection definitions (must match connection_id in routes)

[[bot.connections]]
id = "qq-main"
provider = "qq"
domain = "qq"
label = "QQ Bot"
enabled = true

[[bot.connections]]
id = "feishu-main"
provider = "feishu"
domain = "feishu"
label = "Feishu Bot"
enabled = true

Adding WeChat (Weixin) Routes

Add WeChat-specific routing by specifying platform = "weixin":

[[bot.routes]]
connection_id = "weixin-main"
platform = "weixin"
chat_type = "dm"
user_id = "wx_user_abc"
workspace_root = "/projects/wechat-dev"
model = "deepseek-coder-v2"
tool_approval_mode = "ask"

Ensure the connection_id matches an entry in [[bot.connections]] with provider = "weixin".

How the Gateway Processes Messages

The message handling flow follows three distinct phases:

  1. Configuration Loading – internal/config/render.go writes TOML sections to the user config file, parsing the [[bot.routes]] array.
  2. Runtime Initialization – internal/botruntime/runtime.go converts BotRouteConfig slices into bot.RouteConfig objects, normalizing tool_approval_mode values.
  3. Admission and Routing – internal/gateway/gateway.go first validates the sender against the allowlist (line ~1046), then iterates routes in order (line ~745) to find the first match where non-empty fields equal the incoming message attributes.

If a route matches, the gateway overrides the default Model, WorkspaceRoot, and ToolApprovalMode for that specific turn, affecting model selection and tool-approval prompts.

Summary

  • [bot.allowlist] provides global access control, rejecting unauthorized users before any routing occurs.
  • [[bot.routes]] enables platform-specific overrides for QQ, Feishu, and WeChat, supporting distinct workspaces, models, and approval modes per chat or user.
  • First-match-wins logic applies routes in order, with empty fields functioning as wildcards.
  • Connection IDs must align between [[bot.connections]] and connection_id fields in routes.
  • Configuration resides in the global TOML file (e.g., reasonix.toml), accessible via the Desktop UI under Settings → Bots.

Frequently Asked Questions

What is the difference between allowlist and routes?

The allowlist ([bot.allowlist]) is a security gate that determines whether a user may interact with the bot at all, acting as a fallback when per-connection access controls are absent. routes ([[bot.routes]]) handle message processing after admission, determining which model, workspace, and tool-approval mode apply to a specific conversation. The allowlist runs first; routes execute only if the user passes the allowlist check.

Can I use wildcards in route matching?

Yes. In [[bot.routes]], any empty field acts as a wildcard that matches all values. For example, omitting user_id creates a route that applies to all users within the specified chat_id and platform. The gateway evaluates routes sequentially and applies the first match it encounters.

How do I find the correct connection_id for my IM platform?

The connection_id must match the id field defined in a [[bot.connections]] entry. For example, if you define id = "qq-main" in the connections table, your route must specify connection_id = "qq-main". These connections are typically configured through the Desktop UI or manually in the TOML file under internal/config/config.go structure (BotConnectionConfig at lines 66-86).

What happens if no route matches an incoming message?

If no route matches, the gateway uses the default values defined in the root [bot] section of your configuration, specifically the model, tool_approval_mode, and workspace settings. The message still processes through the allowlist check, but routing defaults to global bot settings rather than customized per-chat behavior.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →