Skip to content

OpenClaw 支持通过 Socket Mode(默认,适合内网、无公网环境)或 HTTP Request URLs(适合公网服务器、负载均衡)接入 Slack。快速配置需安装插件、创建 Slack App 并获取 Token,然后使用 openclaw config patch 命令或环境变量设置。默认模式为 Socket Mode,生产就绪;支持多账号、斜杠命令、流式输出、附件视觉、执行审批等功能。

OpenClaw 怎么接入 Slack?Socket Mode 与 HTTP 模式配置

生产就绪,支持通过 Slack App 集成的私信和频道。默认模式为 Socket Mode,也支持 HTTP Request URLs。

配对

Slack 私信默认使用配对模式。

斜杠命令

原生命令行为和命令目录。

通道故障排查

跨通道诊断和修复手册。

选择 Socket Mode 还是 HTTP Request URLs

两种传输模式都生产就绪,在消息、斜杠命令、App Home 和交互性上功能一致。根据部署形态选择,而不是功能差异。

考虑因素Socket Mode(默认)HTTP Request URLs
公网 Gateway URL不需要需要(DNS、TLS、反向代理或隧道)
出站网络必须能连接 wss-primary.slack.com(出站 WSS)无出站 WebSocket;仅入站 HTTPS
需要的 TokenBot Token (xoxb-...) + App-Level Token (xapp-...) 带 connections:writeBot Token (xoxb-...) + Signing Secret
开发笔记本 / 防火墙后开箱即用需要公网隧道(ngrok、Cloudflare Tunnel、Tailscale Funnel)或暂存 Gateway
水平扩展每个 App 每主机一个 Socket Mode 会话;多个 Gateway 需不同 Slack App无状态 POST 处理器;多个 Gateway 副本可共享一个 App 在负载均衡后
单 Gateway 多账号支持;每个账号打开自己的 WebSocket支持;每个账号需要唯一的 webhookPath(默认 /slack/events)以避免注册冲突
斜杠命令传输通过 WebSocket 连接传递;slash_commands[].url 被忽略Slack POST 到 slash_commands[].url;该字段对于命令分发是必需的
请求签名不使用(认证是 App-Level Token)Slack 签名每个请求;OpenClaw 用 signingSecret 验证
连接断开恢复Slack SDK 自动重连已启用;OpenClaw 也会重启失败的 Socket Mode 会话(有界退避)。Pong 超时传输调优适用。无持久连接可断;重试是 Slack 对每个请求的

INFO

选 Socket Mode 适用于单 Gateway 主机、开发笔记本和能出站连接 *.slack.com 但不能接受入站 HTTPS 的企业内网。

选 HTTP Request URLs 适用于在负载均衡后运行多个 Gateway 副本、出站 WSS 被阻止但入站 HTTPS 允许、或已在反向代理处终止 Slack webhook 的情况。

安装

在配置通道前安装 Slack 插件:

bash
openclaw plugins install @openclaw/slack

plugins install 注册并启用插件。插件在配置 Slack App 和通道设置前不会起作用。参见 插件 了解通用插件行为。

快速设置

Socket Mode(默认)

创建新的 Slack App

    打开 [api.slack.com/apps](https://api.slack.com/apps/new) → **Create New App** → **From a manifest** → 选择你的工作区 → 粘贴以下 Manifest 之一 → **Next** → **Create**。
json
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": { "display_name": "OpenClaw", "always_online": true },
    "app_home": {
      "home_tab_enabled": true,
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "assistant_view": {
      "assistant_description": "OpenClaw connects Slack assistant threads to OpenClaw agents.",
      "suggested_prompts": [
        { "title": "What can you do?", "message": "What can you help me with?" },
        {
          "title": "Summarize this channel",
          "message": "Summarize the recent activity in this channel."
        },
        { "title": "Draft a reply", "message": "Help me draft a reply." }
      ]
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "app_mentions:read",
        "assistant:write",
        "channels:history",
        "channels:read",
        "chat:write",
        "commands",
        "emoji:read",
        "files:read",
        "files:write",
        "groups:history",
        "groups:read",
        "im:history",
        "im:read",
        "im:write",
        "mpim:history",
        "mpim:read",
        "mpim:write",
        "pins:read",
        "pins:write",
        "reactions:read",
        "reactions:write",
        "usergroups:read",
        "users:read"
      ]
    }
  },
  "settings": {
    "socket_mode_enabled": true,
    "event_subscriptions": {
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "channel_rename",
        "member_joined_channel",
        "member_left_channel",
        "message.channels",
        "message.groups",
        "message.im",
        "message.mpim",
        "pin_added",
        "pin_removed",
        "reaction_added",
        "reaction_removed"
      ]
    }
  }
}
json
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": { "display_name": "OpenClaw", "always_online": true },
    "app_home": {
      "home_tab_enabled": true,
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "assistant_view": {
      "assistant_description": "OpenClaw connects Slack assistant threads to OpenClaw agents.",
      "suggested_prompts": [
        { "title": "What can you do?", "message": "What can you help me with?" },
        {
          "title": "Summarize this channel",
          "message": "Summarize the recent activity in this channel."
        },
        { "title": "Draft a reply", "message": "Help me draft a reply." }
      ]
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "app_mentions:read",
        "assistant:write",
        "channels:history",
        "channels:read",
        "chat:write",
        "commands",
        "groups:history",
        "groups:read",
        "im:history",
        "im:read",
        "im:write",
        "users:read"
      ]
    }
  },
  "settings": {
    "socket_mode_enabled": true,
    "event_subscriptions": {
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "message.channels",
        "message.groups",
        "message.im"
      ]
    }
  }
}

INFO

      **Recommended** 匹配 Slack 插件的完整功能集:App Home、斜杠命令、文件、反应、Pin、群组私信和表情符号/用户组读取。当工作区策略限制权限时选择 **Minimal**——它覆盖私信、频道/群组历史、提及和斜杠命令,但去掉文件、反应、Pin、群组私信 (`mpim:*`)、`emoji:read` 和 `usergroups:read`。参见 [Manifest 和作用域清单](#manifest-和权限清单) 了解每个作用域的说明和附加选项(如额外的斜杠命令)。
    Slack 创建 App 后:

    - **Basic Information → App-Level Tokens → Generate Token and Scopes**:添加 `connections:write`,保存,复制 `xapp-...` 值。
    - **Install App → Install to Workspace**:复制 `xoxb-...` Bot User OAuth Token。

配置 OpenClaw

    推荐的 SecretRef 设置:
bash
export SLACK_APP_TOKEN=xapp-...
export SLACK_BOT_TOKEN=xoxb-...
cat > slack.socket.patch.json5 <<'JSON5'
{
  channels: {
    slack: {
      enabled: true,
      mode: "socket",
      appToken: { source: "env", provider: "default", id: "SLACK_APP_TOKEN" },
      botToken: { source: "env", provider: "default", id: "SLACK_BOT_TOKEN" },
    },
  },
}
JSON5
openclaw config patch --file ./slack.socket.patch.json5 --dry-run
openclaw config patch --file ./slack.socket.patch.json5
    环境变量回退(仅默认账号):
bash
SLACK_APP_TOKEN=xapp-...
SLACK_BOT_TOKEN=xoxb-...

启动 Gateway

bash
openclaw gateway

HTTP Request URLs

创建新的 Slack App

    打开 [api.slack.com/apps](https://api.slack.com/apps/new) → **Create New App** → **From a manifest** → 选择你的工作区 → 粘贴以下 Manifest 之一 → 将 `https://gateway-host.example.com/slack/events` 替换为你的公网 Gateway URL → **Next** → **Create**。
json
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": { "display_name": "OpenClaw", "always_online": true },
    "app_home": {
      "home_tab_enabled": true,
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "assistant_view": {
      "assistant_description": "OpenClaw connects Slack assistant threads to OpenClaw agents.",
      "suggested_prompts": [
        { "title": "What can you do?", "message": "What can you help me with?" },
        {
          "title": "Summarize this channel",
          "message": "Summarize the recent activity in this channel."
        },
        { "title": "Draft a reply", "message": "Help me draft a reply." }
      ]
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false,
        "url": "https://gateway-host.example.com/slack/events"
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "app_mentions:read",
        "assistant:write",
        "channels:history",
        "channels:read",
        "chat:write",
        "commands",
        "emoji:read",
        "files:read",
        "files:write",
        "groups:history",
        "groups:read",
        "im:history",
        "im:read",
        "im:write",
        "mpim:history",
        "mpim:read",
        "mpim:write",
        "pins:read",
        "pins:write",
        "reactions:read",
        "reactions:write",
        "usergroups:read",
        "users:read"
      ]
    }
  },
  "settings": {
    "event_subscriptions": {
      "request_url": "https://gateway-host.example.com/slack/events",
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "channel_rename",
        "member_joined_channel",
        "member_left_channel",
        "message.channels",
        "message.groups",
        "message.im",
        "message.mpim",
        "pin_added",
        "pin_removed",
        "reaction_added",
        "reaction_removed"
      ]
    },
    "interactivity": {
      "is_enabled": true,
      "request_url": "https://gateway-host.example.com/slack/events",
      "message_menu_options_url": "https://gateway-host.example.com/slack/events"
    }
  }
}
json
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": { "display_name": "OpenClaw", "always_online": true },
    "app_home": {
      "home_tab_enabled": true,
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "assistant_view": {
      "assistant_description": "OpenClaw connects Slack assistant threads to OpenClaw agents.",
      "suggested_prompts": [
        { "title": "What can you do?", "message": "What can you help me with?" },
        {
          "title": "Summarize this channel",
          "message": "Summarize the recent activity in this channel."
        },
        { "title": "Draft a reply", "message": "Help me draft a reply." }
      ]
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false,
        "url": "https://gateway-host.example.com/slack/events"
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "app_mentions:read",
        "assistant:write",
        "channels:history",
        "channels:read",
        "chat:write",
        "commands",
        "groups:history",
        "groups:read",
        "im:history",
        "im:read",
        "im:write",
        "users:read"
      ]
    }
  },
  "settings": {
    "event_subscriptions": {
      "request_url": "https://gateway-host.example.com/slack/events",
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "message.channels",
        "message.groups",
        "message.im"
      ]
    },
    "interactivity": {
      "is_enabled": true,
      "request_url": "https://gateway-host.example.com/slack/events",
      "message_menu_options_url": "https://gateway-host.example.com/slack/events"
    }
  }
}

INFO

      **Recommended** 匹配 Slack 插件的完整功能集;**Minimal** 去除文件、反应、Pin、群组私信 (`mpim:*`)、`emoji:read` 和 `usergroups:read` 以应对限制严格的工作区。参见 [Manifest 和作用域清单](#manifest-和权限清单) 了解每个作用域说明。

INFO

      三个 URL 字段(`slash_commands[].url`、`event_subscriptions.request_url`、`interactivity.request_url` / `message_menu_options_url`)都指向同一个 OpenClaw 端点。Slack Manifest 要求分别命名,但 OpenClaw 按负载类型路由,所以一个 `webhookPath`(默认 `/slack/events`)就够了。没有 `slash_commands[].url` 的斜杠命令在 HTTP 模式下会静默无操作。
    Slack 创建 App 后:

    - **Basic Information → App Credentials**:复制 **Signing Secret** 用于请求验证。
    - **Install App → Install to Workspace**:复制 `xoxb-...` Bot User OAuth Token。

配置 OpenClaw

    推荐的 SecretRef 设置:
bash
export SLACK_BOT_TOKEN=xoxb-...
export SLACK_SIGNING_SECRET=...
cat > slack.http.patch.json5 <<'JSON5'
{
  channels: {
    slack: {
      enabled: true,
      mode: "http",
      botToken: { source: "env", provider: "default", id: "SLACK_BOT_TOKEN" },
      signingSecret: { source: "env", provider: "default", id: "SLACK_SIGNING_SECRET" },
      webhookPath: "/slack/events",
    },
  },
}
JSON5
openclaw config patch --file ./slack.http.patch.json5 --dry-run
openclaw config patch --file ./slack.http.patch.json5

INFO

    多账号 HTTP 模式下,每个账号使用唯一 `webhookPath`(默认 `/slack/events`)以避免注册冲突。

启动 Gateway

bash
openclaw gateway

Socket Mode 传输调优

OpenClaw 默认将 Slack SDK 客户端 pong 超时设为 15 秒(Socket Mode)。仅在需要工作区或主机特定调优时覆盖传输设置:

json5
{
  channels: {
    slack: {
      mode: "socket",
      socketMode: {
        clientPingTimeout: 20000,
        serverPingTimeout: 30000,
        pingPongLoggingEnabled: false,
      },
    },
  },
}

仅用于 Socket Mode 工作区中记录 Slack WebSocket pong/服务器 ping 超时,或在已知事件循环饥饿的主机上使用。clientPingTimeout 是 SDK 发送客户端 ping 后的 pong 等待时间;serverPingTimeout 是等待 Slack 服务器 ping 的时间。App 消息和事件仍是应用状态,不是传输活性信号。

说明:

  • socketMode 在 HTTP Request URL 模式下被忽略。
  • 基础 channels.slack.socketMode 设置适用于所有 Slack 账号,除非被覆盖。每账号覆盖使用 channels.slack.accounts.<accountId>.socketMode;因为是对象覆盖,需要包含该账号的每个调优字段。
  • 只有 clientPingTimeout 有 OpenClaw 默认值 (15000)。serverPingTimeoutpingPongLoggingEnabled 仅在配置时传递给 Slack SDK。
  • Socket Mode 重启退避从约 2 秒开始,上限约 30 秒。连续可恢复的启动/启动等待失败在 12 次尝试后停止;成功连接后,后续可恢复断开会触发新的重试周期。不可恢复的 Slack 认证错误(如 invalid_auth、撤销的 Token、缺少作用域)快速失败,不会无限重试。

Manifest 和权限清单

基础的 Slack App Manifest 对 Socket Mode 和 HTTP Request URLs 相同。只有 settings 块(和斜杠命令 url)不同。

基础 Manifest(Socket Mode 默认):

json
{
  "display_information": {
    "name": "OpenClaw",
    "description": "Slack connector for OpenClaw"
  },
  "features": {
    "bot_user": { "display_name": "OpenClaw", "always_online": true },
    "app_home": {
      "home_tab_enabled": true,
      "messages_tab_enabled": true,
      "messages_tab_read_only_enabled": false
    },
    "assistant_view": {
      "assistant_description": "OpenClaw connects Slack assistant threads to OpenClaw agents.",
      "suggested_prompts": [
        { "title": "What can you do?", "message": "What can you help me with?" },
        {
          "title": "Summarize this channel",
          "message": "Summarize the recent activity in this channel."
        },
        { "title": "Draft a reply", "message": "Help me draft a reply." }
      ]
    },
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false
      }
    ]
  },
  "oauth_config": {
    "scopes": {
      "bot": [
        "app_mentions:read",
        "assistant:write",
        "channels:history",
        "channels:read",
        "chat:write",
        "commands",
        "emoji:read",
        "files:read",
        "files:write",
        "groups:history",
        "groups:read",
        "im:history",
        "im:read",
        "im:write",
        "mpim:history",
        "mpim:read",
        "mpim:write",
        "pins:read",
        "pins:write",
        "reactions:read",
        "reactions:write",
        "usergroups:read",
        "users:read"
      ]
    }
  },
  "settings": {
    "socket_mode_enabled": true,
    "event_subscriptions": {
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "channel_rename",
        "member_joined_channel",
        "member_left_channel",
        "message.channels",
        "message.groups",
        "message.im",
        "message.mpim",
        "pin_added",
        "pin_removed",
        "reaction_added",
        "reaction_removed"
      ]
    }
  }
}

对于 HTTP Request URLs 模式,将 settings 替换为 HTTP 变体,并为每个斜杠命令添加 url。公网 URL 是必需的:

json
{
  "features": {
    "slash_commands": [
      {
        "command": "/openclaw",
        "description": "Send a message to OpenClaw",
        "should_escape": false,
        "url": "https://gateway-host.example.com/slack/events"
      }
    ]
  },
  "settings": {
    "event_subscriptions": {
      "request_url": "https://gateway-host.example.com/slack/events",
      "bot_events": [
        "app_home_opened",
        "app_mention",
        "assistant_thread_context_changed",
        "assistant_thread_started",
        "channel_rename",
        "member_joined_channel",
        "member_left_channel",
        "message.channels",
        "message.groups",
        "message.im",
        "message.mpim",
        "pin_added",
        "pin_removed",
        "reaction_added",
        "reaction_removed"
      ]
    },
    "interactivity": {
      "is_enabled": true,
      "request_url": "https://gateway-host.example.com/slack/events",
      "message_menu_options_url": "https://gateway-host.example.com/slack/events"
    }
  }
}

附加 Manifest 设置

以下选项扩展上述默认 Manifest。

默认 Manifest 启用了 Slack App Home 的 Home 选项卡并订阅了 app_home_opened。当工作区成员打开 Home 选项卡时,OpenClaw 用 views.publish 发布安全的默认 Home 视图;不含对话负载或私密配置。Messages 选项卡保持启用用于 Slack 私信。Manifest 还通过 features.assistant_viewassistant:writeassistant_thread_startedassistant_thread_context_changed 启用了 Slack 辅助线程;辅助线程路由到自己的 OpenClaw 线程会话,并使 Slack 提供的线程上下文对智能体可用。

可选的原生斜杠命令

可以使用多个[原生斜杠命令](#命令和斜杠行为)替代单个配置命令,但有一些细微差别:

- 使用 `/agentstatus` 代替 `/status`,因为 `/status` 命令被 Slack 保留。
- 一次最多可注册 25 个斜杠命令。

替换现有 `features.slash_commands` 部分为[可用命令](/ai/ai-tools/openclaw/tools/slash-commands#命令列表)的子集:

Socket Mode(默认)

json
{
  "slash_commands": [
    {
      "command": "/new",
      "description": "Start a new session",
      "usage_hint": "[model]"
    },
    {
      "command": "/reset",
      "description": "Reset the current session"
    },
    {
      "command": "/compact",
      "description": "Compact the session context",
      "usage_hint": "[instructions]"
    },
    {
      "command": "/stop",
      "description": "Stop the current run"
    },
    {
      "command": "/session",
      "description": "Manage thread-binding expiry",
      "usage_hint": "idle <duration|off> or max-age <duration|off>"
    },
    {
      "command": "/think",
      "description": "Set the thinking level",
      "usage_hint": "<level>"
    },
    {
      "command": "/verbose",
      "description": "Toggle verbose output",
      "usage_hint": "on|off|full"
    },
    {
      "command": "/fast",
      "description": "Show or set fast mode",
      "usage_hint": "[status|on|off]"
    },
    {
      "command": "/reasoning",
      "description": "Toggle reasoning visibility",
      "usage_hint": "[on|off|stream]"
    },
    {
      "command": "/elevated",
      "description": "Toggle elevated mode",
      "usage_hint": "[on|off|ask|full]"
    },
    {
      "command": "/exec",
      "description": "Show or set exec defaults",
      "usage_hint": "host=<auto|sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>"
    },
    {
      "command": "/approve",
      "description": "Approve or deny pending approval requests",
      "usage_hint": "<id> <decision>"
    },
    {
      "command": "/model",
      "description": "Show or set the model",
      "usage_hint": "[name|#|status]"
    },
    {
      "command": "/models",
      "description": "List providers/models",
      "usage_hint": "[provider] [page] [limit=<n>|size=<n>|all]"
    },
    {
      "command": "/help",
      "description": "Show the short help summary"
    },
    {
      "command": "/commands",
      "description": "Show the generated command catalog"
    },
    {
      "command": "/tools",
      "description": "Show what the current agent can use right now",
      "usage_hint": "[compact|verbose]"
    },
    {
      "command": "/agentstatus",
      "description": "Show runtime status, including provider usage/quota when available"
    },
    {
      "command": "/tasks",
      "description": "List active/recent background tasks for the current session"
    },
    {
      "command": "/context",
      "description": "Explain how context is assembled",
      "usage_hint": "[list|detail|json]"
    },
    {
      "command": "/whoami",
      "description": "Show your sender identity"
    },
    {
      "command": "/skill",
      "description": "Run a skill by name",
      "usage_hint": "<name> [input]"
    },
    {
      "command": "/btw",
      "description": "Ask a side question without changing session context",
      "usage_hint": "<question>"
    },
    {
      "command": "/side",
      "description": "Ask a side question without changing session context",
      "usage_hint": "<question>"
    },
    {
      "command": "/usage",
      "description": "Control the usage footer or show cost summary",
      "usage_hint": "off|tokens|full|cost"
    }
  ]
}

HTTP Request URLs

    使用与 Socket Mode 相同的 `slash_commands` 列表,并在每个条目中添加 `"url": "https://gateway-host.example.com/slack/events"`。例如:
json
{
  "slash_commands": [
    {
      "command": "/new",
      "description": "Start a new session",
      "usage_hint": "[model]",
      "url": "https://gateway-host.example.com/slack/events"
    },
    {
      "command": "/help",
      "description": "Show the short help summary",
      "url": "https://gateway-host.example.com/slack/events"
    }
  ]
}
    对列表中每个命令重复该 `url` 值。

可选的作者作用域(写操作)

添加 `chat:write.customize` 机器人作用域,以便出站消息使用当前智能体身份(自定义用户名和图标)而非默认 Slack App 身份。

如果使用表情符号图标,Slack 要求 `:emoji_name:` 语法。

可选的用户 Token 作用域(读操作)

如果配置了 `channels.slack.userToken`,典型读作用域包括:

- `channels:history`、`groups:history`、`im:history`、`mpim:history`
- `channels:read`、`groups:read`、`im:read`、`mpim:read`
- `users:read`
- `reactions:read`
- `pins:read`
- `emoji:read`
- `search:read`(如果依赖 Slack 搜索读取)

Token 模型

  • botToken + appToken 是 Socket Mode 必需的。
  • HTTP 模式需要 botToken + signingSecret
  • botTokenappTokensigningSecretuserToken 可接受明文字符串或 SecretRef 对象。
  • 配置中的 Token 覆盖环境变量回退。
  • SLACK_BOT_TOKEN / SLACK_APP_TOKEN 环境变量回退仅适用于默认账号。
  • userTokenxoxp-...)仅支持配置(无环境变量回退),默认为只读行为(userTokenReadOnly: true)。

状态快照行为:

  • Slack 账号检查追踪每个凭证的 *Source*Status 字段(botTokenappTokensigningSecretuserToken)。
  • 状态为 availableconfigured_unavailablemissing
  • configured_unavailable 表示账号通过 SecretRef 或其他非内联密钥来源配置,但当前命令/运行时路径无法解析实际值。
  • 在 HTTP 模式下,包含 signingSecretStatus;在 Socket Mode 下,必需的配对是 botTokenStatus + appTokenStatus

TIP

对于操作/目录读取,已配置时可优先使用用户 Token。对于写入,仍优先使用机器人 Token;仅当 userTokenReadOnly: false 且机器人 Token 不可用时才允许用户 Token 写入。

操作和门禁

Slack 操作由 channels.slack.actions.* 控制。

当前 Slack 工具中可用的操作组:

默认
messages启用
reactions启用
pins启用
memberInfo启用
emojiList启用

当前 Slack 消息操作包括 sendupload-filedownload-filereadeditdeletepinunpinlist-pinsmember-infoemoji-listdownload-file 接受入站文件占位符中显示的 Slack 文件 ID,返回图片预览(图片)或本地文件元数据(其他文件类型)。

访问控制和路由

私信策略

`channels.slack.dmPolicy` 控制私信访问。`channels.slack.allowFrom` 是规范的私信白名单。

- `pairing`(默认)
- `allowlist`
- `open`(需要 `channels.slack.allowFrom` 包含 `"*"`)
- `disabled`

私信相关标志:

- `dm.enabled`(默认 true)
- `channels.slack.allowFrom`
- `dm.allowFrom`(旧版)
- `dm.groupEnabled`(群组私信默认 false)
- `dm.groupChannels`(可选 MPIM 白名单)

多账号优先级:

- `channels.slack.accounts.default.allowFrom` 仅适用于 `default` 账号。
- 命名账号在自身 `allowFrom` 未设置时继承 `channels.slack.allowFrom`。
- 命名账号不继承 `channels.slack.accounts.default.allowFrom`。

旧版 `channels.slack.dm.policy` 和 `channels.slack.dm.allowFrom` 仍会读取以保持兼容性。`openclaw doctor --fix` 会将它们迁移到 `dmPolicy` 和 `allowFrom`(前提是不改变访问权限)。

私信配对使用 `openclaw pairing approve slack <code>`。

频道策略

`channels.slack.groupPolicy` 控制频道处理:

- `open`
- `allowlist`
- `disabled`

频道白名单位于 `channels.slack.channels` 下,**必须使用稳定的 Slack 频道 ID**(例如 `C12345678`)作为配置键。

运行时说明:如果 `channels.slack` 完全缺失(仅环境变量设置),运行时回退到 `groupPolicy="allowlist"` 并记录警告(即使设置了 `channels.defaults.groupPolicy`)。

名称/ID 解析:

- 频道白名单条目和私信白名单条目在启动时解析(Token 权限允许的情况下)
- 未解析的频道名称条目保留在配置中但默认被路由忽略
- 入站授权和频道路由默认以 ID 优先;直接用户名/slug 匹配需要 `channels.slack.dangerouslyAllowNameMatching: true`

WARNING

基于名称的键(`#channel-name` 或 `channel-name`)在 `groupPolicy: "allowlist"` 下**无法匹配**。频道查找默认以 ID 优先,因此基于名称的键永远无法成功路由,该频道中的消息将被静默阻止。这与 `groupPolicy: "open"` 不同,后者不要求频道键用于路由,基于名称的键看起来能工作。

始终使用 Slack 频道 ID 作为键。查找方法:在 Slack 中右键点击频道 → **Copy link** —— ID(`C...`)出现在 URL 末尾。

正确:

```json5
{
  channels: {
    slack: {
      groupPolicy: "allowlist",
      channels: {
        C12345678: { allow: true, requireMention: true },
      },
    },
  },
}
```

错误(在 `groupPolicy: "allowlist"` 下被静默阻止):

```json5
{
  channels: {
    slack: {
      groupPolicy: "allowlist",
      channels: {
        "#eng-my-channel": { allow: true, requireMention: true },
      },
    },
  },
}
```

提及和频道用户

频道消息默认需要 @提及才会响应。

提及来源:

- 显式 App 提及(`<@botId>`)
- Slack 用户组提及(`<!subteam^S...>`)当机器人用户是该用户组成员时;需要 `usergroups:read`
- 提及正则模式(`agents.list[].groupChat.mentionPatterns`,回退 `messages.groupChat.mentionPatterns`)
- 隐式回复机器人线程行为(当 `thread.requireExplicitMention` 为 `true` 时禁用)

每频道控制(`channels.slack.channels.&lt;id&gt;`;名称仅通过启动解析或 `dangerouslyAllowNameMatching` 可用):

- `requireMention`
- `users`(白名单)
- `allowBots`
- `skills`
- `systemPrompt`
- `tools`、`toolsBySender`
- `toolsBySender` key 格式:`channel:`、`id:`、`e164:`、`username:`、`name:` 或 `"*"` 通配符
  (旧版无前缀 key 仍映射到 `id:` 仅)

`allowBots` 对频道和私有频道是保守的:机器人编写的房间消息只有在该房间的 `users` 白名单中显式列出发送机器人,或者至少有一个来自 `channels.slack.allowFrom` 的显式 Slack 所有者 ID 当前是该房间成员时才被接受。通配符和显示名称所有者条目不满足所有者存在条件。所有者存在检查使用 Slack `conversations.members`;确保 App 具有房间类型对应的读取作用域(公共频道需要 `channels:read`,私有频道需要 `groups:read`)。如果成员查找失败,OpenClaw 会丢弃机器人编写的房间消息。

被接受的机器人编写的 Slack 消息使用共享的[机器人循环保护](/ai/ai-tools/openclaw/channels/bot-loop-protection)。通过 `channels.defaults.botLoopProtection` 配置默认预算,然后当工作区或频道需要不同限制时用 `channels.slack.botLoopProtection` 或 `channels.slack.channels.&lt;id&gt;.botLoopProtection` 覆盖。

线程、Session 和回复标签

  • 私信路由为 direct;频道为 channel;多人群组私信为 group
  • Slack 路由绑定接受原始对等 ID 加上 Slack 目标形式,如 channel:C12345678user:U12345678<@U12345678>
  • 默认情况下 session.dmScope=main,Slack 私信折叠到智能体主 session。
  • 频道 session:agent:<agentId>:slack:channel:<channelId>
  • 普通顶层频道消息保留在每频道 session 上,即使 replyToModeoff
  • Slack 线程回复使用父级 thread_ts 作为 session 后缀(:thread:<threadTs>),即使出站回复线程被 replyToMode="off" 禁用。
  • OpenClaw 将一个符合条件的顶层频道根种子到 agent:<agentId>:slack:channel:<channelId>:thread:<rootTs>,当该根预期会启动可见的 Slack 线程时,使得根和后续线程回复共享同一个 OpenClaw session。这适用于 app_mention 事件、显式机器人或配置的提及模式匹配,以及 requireMention: falsereplyToModeoff 的频道。
  • channels.slack.thread.historyScope 默认值为 threadthread.inheritParent 默认值为 false
  • channels.slack.thread.initialHistoryLimit 控制新线程 session 启动时获取的现有线程消息数量(默认 20;设为 0 禁用)。
  • channels.slack.thread.requireExplicitMention(默认 false):当为 true 时,抑制隐式线程提及,以便机器人仅在显式 @bot 提及线程内时才回复,即使机器人已经参与该线程。如果不设置,机器人参与的线程中的回复会绕过 requireMention 门控。

回复线程控制:

  • channels.slack.replyToModeoff|first|all|batched(默认 off
  • channels.slack.replyToModeByChatType:按 direct|group|channel 分别配置
  • 直接聊天的旧版回退:channels.slack.dm.replyToMode

支持手动回复标签:

  • [[reply_to_current]]
  • [[reply_to:&lt;id&gt;]]

对于来自 message 工具的显式 Slack 线程回复,设置 replyBroadcast: trueaction: "send"threadIdreplyTo,要求 Slack 也将线程回复广播到父频道。这映射到 Slack 的 chat.postMessage reply_broadcast 标志,仅支持文本或 Block Kit 发送,不支持媒体上传。

message 工具调用在 Slack 线程内部执行并针对同一频道时,OpenClaw 通常根据 replyToMode 继承当前 Slack 线程。在 action: "send"action: "upload-file" 上设置 topLevel: true 以强制发送新的父频道消息。threadId: null 被接受为相同的顶层退出。

INFO

replyToMode="off" 禁用出站 Slack 回复线程,包括显式 [[reply_to_*]] 标签。它不会展平入站 Slack 线程 session:已经发布在 Slack 线程中的消息仍路由到 :thread:<threadTs> session。这与 Telegram 不同,Telegram 在 "off" 模式下仍尊重显式标签。Slack 线程对频道隐藏消息,而 Telegram 回复保持内联可见。

Ack 反应

ackReaction 在 OpenClaw 处理入站消息时发送确认表情。

解析顺序:

  • channels.slack.accounts.<accountId>.ackReaction
  • channels.slack.ackReaction
  • messages.ackReaction
  • 智能体身份表情回退(agents.list[].identity.emoji,否则 "👀")

说明:

  • Slack 期望简码(例如 "eyes")。
  • 使用 "" 禁用 Slack 账号或全局的反应。

文本流式输出

channels.slack.streaming 控制实时预览行为:

  • off:禁用实时预览流式输出。
  • partial(默认):用最新部分输出替换预览文本。
  • block:追加分块预览更新。
  • progress:生成时显示进度状态文本,完成后发送最终文本。
  • streaming.preview.toolProgress:当草稿预览激活时,将工具/进度更新路由到同一编辑后的预览消息(默认:true)。设为 false 保持单独的工具/进度消息。
  • streaming.preview.commandText / streaming.progress.commandText:设为 status 以保持紧凑的工具进度行,同时隐藏原始命令/执行文本(默认:raw)。

隐藏原始命令/执行文本同时保持紧凑进度行:

json
{
  "channels": {
    "slack": {
      "streaming": {
        "mode": "progress",
        "progress": {
          "toolProgress": true,
          "commandText": "status"
        }
      }
    }
  }
}

channels.slack.streaming.nativeTransport 控制 Slack 原生文本流式输出,当 channels.slack.streaming.modepartial 时(默认:true)。

  • 回复线程必须可用于原生文本流式输出和 Slack 辅助线程状态显示。线程选择仍遵循 replyToMode
  • 频道、群组聊天和顶层私信根当原生流式输出不可用或没有回复线程时,仍可使用普通草稿预览。
  • 顶层 Slack 私信默认脱离线程,因此不显示 Slack 线程风格的原生流式/状态预览;OpenClaw 在私信中发布和编辑草稿预览。
  • 媒体和非文本负载回退到普通交付。
  • 媒体/错误最终结果取消待处理的预览编辑;符合条件的文本/块最终结果仅在它们能编辑预览时才刷新。
  • 如果流式输出中途失败,OpenClaw 对剩余负载回退到普通交付。

使用草稿预览代替 Slack 原生文本流式输出:

json5
{
  channels: {
    slack: {
      streaming: {
        mode: "partial",
        nativeTransport: false,
      },
    },
  },
}

旧版键:

  • channels.slack.streamModereplace | status_final | append)是 channels.slack.streaming.mode 的旧版运行时别名。
  • 布尔值 channels.slack.streamingchannels.slack.streaming.modechannels.slack.streaming.nativeTransport 的旧版运行时别名。
  • 旧版 channels.slack.nativeStreamingchannels.slack.streaming.nativeTransport 的运行时别名。
  • 运行 openclaw doctor --fix 以重写持久化的 Slack 流式配置到规范键。

打字反应回退

typingReaction 在 OpenClaw 处理回复时向入站 Slack 消息添加临时反应,运行完成时移除。在线程回复之外最有用(线程回复默认显示 "is typing..." 状态指示器)。

解析顺序:

  • channels.slack.accounts.<accountId>.typingReaction
  • channels.slack.typingReaction

说明:

  • Slack 期望简码(例如 "hourglass_flowing_sand")。
  • 反应是尽力而为的,回复或失败路径完成后自动尝试清理。

媒体、分块和交付

入站附件

Slack 文件附件从 Slack 托管的私有 URL 下载(Token 认证请求流),获取成功且在大小限制内时写入媒体存储。文件占位符包含 Slack `fileId`,以便智能体可以用 `download-file` 获取原始文件。

下载使用有界的空闲和总超时。如果 Slack 文件检索停滞或失败,OpenClaw 继续处理消息并回退到文件占位符。

运行时入站大小上限默认 `20MB`,除非被 `channels.slack.mediaMaxMb` 覆盖。

出站文本和文件

- 文本块使用 `channels.slack.textChunkLimit`(默认 4000)
- `channels.slack.chunkMode="newline"` 启用段落优先分割
- 文件发送使用 Slack 上传 API,可包含线程回复(`thread_ts`)
- 出站媒体上限遵循 `channels.slack.mediaMaxMb`(已配置时);否则频道发送使用媒体管道中的 MIME 类型默认值

交付目标

首选的显式目标:

- `user:&lt;id&gt;` 用于私信
- `channel:&lt;id&gt;` 用于频道

纯文本/仅块 Slack 私信可以直接发布到用户 ID;文件上传和线程化发送需要先通过 Slack 对话 API 打开私信,因为这些路径需要具体的对话 ID。

命令和斜杠行为

斜杠命令在 Slack 中以单个配置命令或多个原生命令的形式出现。配置 channels.slack.slashCommand 以更改命令默认值:

  • enabled: false
  • name: "openclaw"
  • sessionPrefix: "slack:slash"
  • ephemeral: true
txt
/openclaw /help

原生命令需要在 Slack App 中添加额外 Manifest 设置,并通过 channels.slack.commands.native: true 或全局配置中的 commands.native: true 启用。

  • 原生命令自动模式对 Slack 关闭,因此 commands.native: "auto" 不会启用 Slack 原生命令。
txt
/help

原生参数菜单使用自适应渲染策略,在分发选中的选项值之前显示确认模态:

  • 最多 5 个选项:按钮块
  • 6-100 个选项:静态选择菜单
  • 超过 100 个选项:外部选择(当交互性选项处理器可用时)带异步选项过滤
  • 超出 Slack 限制:编码的选项值回退到按钮
txt
/think

斜杠 session 使用隔离键 agent:<agentId>:slack:slash:<userId>,但命令执行仍路由到目标对话 session(使用 CommandTargetSessionKey)。

交互式回复

Slack 可以渲染智能体编写的交互式回复控件,但此功能默认禁用。 对于新的智能体、CLI 和插件输出,优先使用共享的 presentation 按钮或选择块。它们使用相同的 Slack 交互 路径,同时能在其他通道优雅降级。

全局启用:

json5
{
  channels: {
    slack: {
      capabilities: {
        interactiveReplies: true,
      },
    },
  },
}

或仅对某个 Slack 账号启用:

json5
{
  channels: {
    slack: {
      accounts: {
        ops: {
          capabilities: {
            interactiveReplies: true,
          },
        },
      },
    },
  },
}

启用后,智能体仍可以发出已废弃的 Slack 专用回复指令:

  • [[slack_buttons: Approve:approve, Reject:reject]]
  • [[slack_select: Choose a target | Canary:canary, Production:production]]

这些指令编译成 Slack Block Kit,并通过现有 Slack 交互事件路径路由点击或选择。为旧提示和 Slack 专用逃生口保留它们;新便携式控件使用共享的 presentation。

指令编译器 API 也已废弃,不应用于新的生产者代码:

  • compileSlackInteractiveReplies(...)
  • parseSlackOptionsLine(...)
  • isSlackInteractiveRepliesEnabled(...)
  • buildSlackInteractiveBlocks(...)

对于新的 Slack 渲染控件,使用 presentation 负载和 buildSlackPresentationBlocks(...)

说明:

  • 这是 Slack 专用旧版 UI。其他通道不会将 Slack Block Kit 指令翻译成自己的按钮系统。
  • 交互回调值是 OpenClaw 生成的不透明 token,不是智能体编写的原始值。
  • 如果生成的交互块会超出 Slack Block Kit 限制,OpenClaw 回退到原始文本回复,而不是发送无效的块负载。

插件拥有的模态提交

注册了交互处理器的 Slack 插件也可以在 OpenClaw 压缩负载用于智能体可见的系统事件之前接收模态 view_submissionview_closed 生命周期事件。在打开 Slack 模态时使用以下路由模式之一:

  • callback_id 设置为 openclaw:&lt;namespace&gt;:&lt;payload&gt;
  • 或者保留现有 callback_id,并在模态 private_metadata 中放入 pluginInteractiveData: "&lt;namespace&gt;:&lt;payload&gt;"

处理器接收 ctx.interaction.kind 作为 view_submissionview_closed、规范化 inputs,以及来自 Slack 的完整原始 stateValues 对象。仅回调 ID 路由足以调用插件处理器;当模态还应该产生智能体可见的系统事件时,包含现有模态 private_metadata 用户/session 路由字段。智能体接收到一个紧凑、编辑过的 Slack interaction: ... 系统事件。如果处理器返回 systemEvent.summarysystemEvent.referencesystemEvent.data,这些字段被包含在该紧凑事件中,以便智能体可以引用插件拥有的存储而不看到完整表单负载。

Slack 中的原生审批

Slack 可以作为原生审批客户端,使用交互式按钮和交互,而不是回退到 Web UI 或终端。

  • Exec 和插件审批可以渲染为 Slack 原生 Block Kit 提示。
  • channels.slack.execApprovals.* 保持原生 exec 审批客户端启用和 DM/频道路由配置。
  • Exec 审批私信使用 channels.slack.execApprovals.approverscommands.ownerAllowFrom
  • 当 Slack 作为原生审批客户端为发起 session 启用时,或当 approvals.plugin 路由到发起 Slack session 或 Slack 目标时,插件审批使用 Slack 原生按钮。
  • 插件审批私信使用来自 channels.slack.allowFrom、命名账号 allowFrom 或账号默认路由的 Slack 插件审批者。
  • 审批者授权仍然强制执行:仅 exec 审批者不能批准插件请求,除非他们也是插件审批者。

这使用与其他通道相同的共享审批按钮表面。当 Slack App 设置中启用了 interactivity 时,审批提示直接在对话中渲染为 Block Kit 按钮。 当这些按钮存在时,它们是主要的审批 UX;OpenClaw 只应在工具结果说明聊天审批不可用或手动审批是唯一路径时包含手动 /approve 命令。

配置路径:

  • channels.slack.execApprovals.enabled
  • channels.slack.execApprovals.approvers(可选;无时回退到 commands.ownerAllowFrom
  • channels.slack.execApprovals.targetdm | channel | both,默认:dm
  • agentFiltersessionFilter

Slack 在 enabled 未设置或为 "auto" 且至少一个 exec 审批者解析成功时自动启用原生 exec 审批。Slack 也可以在此原生客户端路径上处理原生插件审批,当 Slack 插件审批者解析成功且请求匹配原生客户端过滤器时。设置 enabled: false 明确禁用 Slack 作为原生审批客户端。设置 enabled: true 在审批者解析成功时强制启用原生审批。禁用 Slack exec 审批不会禁用通过 approvals.plugin 启用的原生 Slack 插件审批交付;插件审批交付使用 Slack 插件审批者。

无显式 Slack exec 审批配置的默认行为:

json5
{
  commands: {
    ownerAllowFrom: ["slack:U12345678"],
  },
}

仅当需要覆盖审批者、添加过滤器或选择来源聊天交付时才需要显式 Slack 原生配置:

json5
{
  channels: {
    slack: {
      execApprovals: {
        enabled: true,
        approvers: ["U12345678"],
        target: "both",
      },
    },
  },
}

共享的 approvals.exec 转发是独立的。仅当 exec 审批提示也必须路由到其他聊天或显式带外目标时才使用它。共享的 approvals.plugin 转发也是独立的;仅当 Slack 无法原生处理插件审批请求时,Slack 原生交付才会抑制该回退。

同聊天 /approve 也在已经支持命令的 Slack 频道和私信中工作。参见 Exec 审批 了解完整审批转发模型。

事件和运行行为

  • 消息编辑/删除映射为系统事件。
  • 线程广播("Also send to channel" 线程回复)作为普通用户消息处理。
  • Reaction 添加/删除事件映射为系统事件。
  • 成员加入/离开、频道创建/重命名、pin 添加/删除事件映射为系统事件。
  • channel_id_changed 在启用 configWrites 时可迁移频道配置键。
  • 频道主题/目的元数据视为不可信上下文,可注入路由上下文。
  • 线程启动者和初始线程历史上下文种子在适用时由配置的发送者白名单过滤。
  • Block actions 和模态交互触发结构化 Slack interaction: ... 系统事件,包含丰富的负载字段:
    • block actions:选中值、标签、选择器值和 workflow_* 元数据
    • 模态 view_submissionview_closed 事件,包含路由频道元数据和表单输入

配置参考

主要参考:配置参考 - Slack

高信号 Slack 字段

  • 模式/认证:modebotTokenappTokensigningSecretwebhookPathaccounts.*
  • 私信访问:dm.enableddmPolicyallowFrom(旧版:dm.policydm.allowFrom)、dm.groupEnableddm.groupChannels
  • 兼容性开关:dangerouslyAllowNameMatching(紧急开关;除非需要否则保持关闭)
  • 频道访问:groupPolicychannels.*channels.*.userschannels.*.requireMention
  • 线程/历史:replyToModereplyToModeByChatTypethread.*historyLimitdmHistoryLimitdms.*.historyLimit
  • 交付:textChunkLimitchunkModemediaMaxMbstreamingstreaming.nativeTransportstreaming.preview.toolProgress
  • 预览展开:unfurlLinks(默认:false)、unfurlMedia 用于 chat.postMessage 链接/媒体预览控制;设置 unfurlLinks: true 重新加入链接预览
  • 运维/功能:configWritescommands.nativeslashCommand.*actions.*userTokenuserTokenReadOnly

故障排查

频道中无回复

按顺序检查:

- `groupPolicy`
- 频道白名单(`channels.slack.channels`)—— **键必须是频道 ID**(`C12345678`),而不是名称(`#channel-name`)。基于名称的键在 `groupPolicy: "allowlist"` 下会静默失败,因为频道路由默认以 ID 优先。要查找 ID:在 Slack 中右键点击频道 → **Copy link** —— URL 末尾的 `C...` 值就是频道 ID。
- `requireMention`
- 每频道 `users` 白名单
- `messages.groupChat.visibleReplies`:普通群组/频道请求默认值为 `"automatic"`。如果你选择了 `"message_tool"` 且日志显示智能体文本但没有 `message(action=send)` 调用,模型错过了可见的消息工具路径。最终文本在此模式下保持私有;检查 Gateway 详细日志以查看被抑制的负载元数据,或设置为 `"automatic"` 以让每个普通智能体最终回复通过旧路径发布。
- `messages.groupChat.unmentionedInbound`:如果它是 `"room_event"`,未提及的允许频道对话是环境上下文,除非智能体调用 `message` 工具否则保持沉默。参见 [环境房间事件](/ai/ai-tools/openclaw/channels/ambient-room-events)。
json5
{
  messages: {
    groupChat: {
      visibleReplies: "automatic",
    },
  },
}
有用命令:
bash
openclaw channels status --probe
openclaw logs --follow
openclaw doctor

私信消息被忽略

检查:

- `channels.slack.dm.enabled`
- `channels.slack.dmPolicy`(或旧版 `channels.slack.dm.policy`)
- 配对审批 / 白名单条目(`dmPolicy: "open"` 仍然需要 `channels.slack.allowFrom: ["*"]`)
- 群组私信使用 MPIM 处理;启用 `channels.slack.dm.groupEnabled`,如果已配置,将 MPIM 包含在 `channels.slack.dm.groupChannels` 中
- Slack 辅助私信事件:详细日志中提到 `drop message_changed` 通常意味着 Slack 发送了一个编辑过的辅助线程事件,消息元数据中没有可恢复的人类发送者
bash
openclaw pairing list slack

Socket Mode 无法连接

验证机器人 Token + App Token 和 Slack App 设置中的 Socket Mode 启用状态。
`xapp-...` App-Level Token 需要 `connections:write`,`xoxb-...` 机器人 Token 必须与 App Token 属于同一个 Slack App/工作区。

如果 `openclaw channels status --probe --json` 显示 `botTokenStatus` 或 `appTokenStatus: "configured_unavailable"`,说明 Slack 账号已配置但当前运行时无法解析 SecretRef 后端的值。

日志如 `slack socket mode failed to start; retry ...` 是可恢复的启动失败。缺少作用域、撤销的 Token 和无效认证会快速失败,不会重试。`slack token mismatch ...` 日志意味着机器人 Token 和 App Token 似乎属于不同的 Slack App;修复 Slack App 凭据。

HTTP 模式未收到事件

验证:

- signing secret
- webhook 路径
- Slack Request URLs(Events + Interactivity + Slash Commands)
- 每个 HTTP 账号使用唯一 `webhookPath`
- 公网 URL 终止 TLS 并将请求转发到 Gateway 路径
- Slack App `request_url` 路径与 `channels.slack.webhookPath`(默认 `/slack/events`)完全匹配

如果账号快照中出现 `signingSecretStatus: "configured_unavailable"`,说明 HTTP 账号已配置但当前运行时无法解析 SecretRef 后端的 signing secret。

重复的 `slack: webhook path ... already registered` 日志意味着两个 HTTP 账号使用了相同的 `webhookPath`;给每个账号分配不同的路径。

原生/斜杠命令不触发

检查你预期的是哪种模式:

- 原生命令模式(`channels.slack.commands.native: true`)+ 在 Slack 中注册匹配的斜杠命令
- 或单斜杠命令模式(`channels.slack.slashCommand.enabled: true`)

Slack 不会自动创建或删除斜杠命令。`commands.native: "auto"` 不会启用 Slack 原生命令;使用 `true` 并在 Slack App 中创建匹配的命令。在 HTTP 模式下,每个 Slack 斜杠命令必须包含 Gateway URL。在 Socket Mode 下,命令负载通过 WebSocket 到达,Slack 会忽略 `slash_commands[].url`。

同时检查 `commands.useAccessGroups`、私信授权、频道白名单和每频道 `users` 白名单。Slack 对被阻止的斜杠命令发送者返回临时错误,包括:

- `This channel is not allowed.`
- `You are not authorized to use this command here.`

附件视觉参考

Slack 可以在 Slack 文件下载成功且大小限制允许时将下载的媒体附加到智能体轮次。图片文件可以通过媒体理解路径或直接传递给视觉能力回复模型;其他文件保留为可下载的文件上下文,而不是作为图像输入处理。

支持的媒体类型

媒体类型来源当前行为说明
JPEG / PNG / GIF / WebP 图片Slack 文件 URL下载并附加到轮次用于视觉能力处理每文件上限:channels.slack.mediaMaxMb(默认 20 MB)
PDF 文件Slack 文件 URL下载并作为文件上下文暴露给工具(如 download-filepdfSlack 入站不会自动将 PDF 转换为图像视觉输入
其他文件Slack 文件 URL尽可能下载并作为文件上下文暴露二进制文件不作为图像输入处理
线程回复线程启动者文件根消息文件可在回复没有直接媒体时作为上下文水化仅文件启动者使用附件占位符
多图片消息多个 Slack 文件每个文件独立评估Slack 处理每消息最多八个文件

入站管道

当带有文件附件的 Slack 消息到达时:

  1. OpenClaw 使用机器人 Token(xoxb-...)从 Slack 私有 URL 下载文件。
  2. 成功时文件写入媒体存储。
  3. 下载的媒体路径和内容类型添加到入站上下文。
  4. 图像能力模型/工具路径可以使用该上下文中的图像附件。
  5. 非图像文件保持为文件元数据或媒体引用,供能处理它们的工具使用。

线程根附件继承

当消息到达一个线程(有 thread_ts 父级)时:

  • 如果回复本身没有直接媒体且包含的根消息有文件,Slack 可以将根文件作为线程启动者上下文水化。
  • 直接回复附件优先于根消息附件。
  • 仅包含文件且没有文本的根消息用附件占位符表示,以便回退仍能包含其文件。

多附件处理

当单个 Slack 消息包含多个文件附件时:

  • 每个附件通过媒体管道独立处理。
  • 下载的媒体引用聚合到消息上下文。
  • 处理顺序遵循事件负载中的 Slack 文件顺序。
  • 一个附件下载失败不会阻止其他附件。

大小、下载和模型限制

  • 大小上限:默认每文件 20 MB。可通过 channels.slack.mediaMaxMb 配置。
  • 下载失败:Slack 无法提供的文件、过期 URL、不可访问的文件、超大文件以及 Slack 认证/登录 HTML 响应被跳过,而不是报告为不支持格式。
  • 视觉模型:图像分析使用活跃的回复模型(当它支持视觉时),或者使用 agents.defaults.imageModel 配置的图像模型。

已知限制

场景当前行为解决方法
Slack 文件 URL 过期文件被跳过;不显示错误在 Slack 中重新上传文件
未配置视觉模型图像附件作为媒体引用存储,但不作为图像分析配置 agents.defaults.imageModel 或使用视觉能力回复模型
非常大的图像(默认 > 20 MB)根据大小上限跳过如果 Slack 允许,增加 channels.slack.mediaMaxMb
转发的/共享的附件文本和 Slack 托管的图像/文件媒体尽力而为直接在 OpenClaw 线程中重新分享
PDF 附件作为文件/媒体上下文存储,不会自动通过图像视觉路由使用 download-file 获取文件元数据或 pdf 工具进行 PDF 分析

相关文档

相关链接

配对

将 Slack 用户配对到 Gateway。

群组

频道和群组私信行为。

频道路由

将入站消息路由到智能体。

安全

威胁模型和加固。

配置

配置布局和优先级。

斜杠命令

命令目录和行为。

常见问题

为什么频道里 @ 了机器人没有响应?

最常见的原因是 groupPolicy 设置为 allowlist 但该频道不在白名单里,或者 requireMention 开启但没有订阅 app_mention 事件。用 openclaw channels status --probeopenclaw logs --follow 诊断。另外确认频道白名单键使用的是 ID(如 C12345678)而不是名称(如 #channel-name)。

Socket Mode 和 HTTP 模式该选哪个?

个人项目或内网环境推荐 Socket Mode,OpenClaw 主动连接 Slack 不需要公网地址。HTTP 模式适合有公网可访问地址的服务器,Slack 会主动推送事件过来,延迟更低,稳定性更好。如果需要在负载均衡后运行多个 Gateway 副本,必须选 HTTP 模式。

如何限制只有特定用户可以和机器人在 Slack 里聊天?

私信使用 dmPolicy: "allowlist" + allowFrom: ["U12345678", "U87654321"] 白名单控制。频道内可以在 channels.slack.channels.<channelId>.users 里设置每频道用户白名单。配对模式(默认)需要通过 openclaw pairing approve slack <code> 手动审批。