openclaw.connect('slack')
/** 您的 AI 队友,7x24 小时在每个 Slack 工作区频道待命 */
## 步骤 1:创建 Slack 应用
## 步骤 2:配置 OpenClaw
// 💡 提示:如果没有公网 URL,请使用 ngrok 或 Cloudflare Tunnel 将本地 3000 端口暴露出来
💬 示例消息
• @alice 交付了登录重构 — 已合并至 main
• @bob:完成了数据库迁移测试,下午 2 点发布
• @carlos:在等新控制台的设计评审,被阻塞
⚠ 风险点:@carlos 需要在下班前获得设计确认
动手之前先定传输方式
这是第一个决定,也是回头代价最大的一个,因为两种模式对应的 Slack app manifest 不一样。消息和斜杠命令两边功能对等,所以问题纯粹在于你的网络环境和你跑几个网关。
| 你的情况 | 传输方式 | 理由 |
|---|---|---|
| 笔记本或家庭服务器上的单个网关 | Socket Mode | 不需要入站端口、公网域名,也不用维护 TLS 证书。 |
| 公司网络封了入站 HTTPS | Socket Mode | 只需要到 wss-primary.slack.com 的出站 WSS。 |
| 负载均衡后面多个网关副本 | HTTP | Socket Mode 把 app-level token 绑在一条连接上,拆到多副本不是它的设计形态。 |
| 策略上禁止出站 WSS | HTTP | 这是唯一一种 Socket Mode 对你根本不可用的情况。 |
| 你本来就在为别的服务做 HTTPS 终止 | HTTP | 差别不大,但省掉一条需要一直保活的长连接。 |
对自托管 Agent 来说,Socket Mode 是正确的默认值。它让你得到一个完全没有公网攻击面的 Slack 集成——这一点在这里比对普通机器人更重要,因为连接另一端那个东西能执行 shell 命令。
Socket Mode 从头到尾
这里涉及两个 token,而且很容易搞混。app-level token 授权的是那条 websocket 本身;bot token 授权的是消息流起来之后的各种动作。一个对一个错的结果是:连接建立了,然后什么都不发生。
# api.slack.com/apps → your app → Basic Information # Generate an App-Level Token with scope: connections:write # Then: OAuth & Permissions → install to workspace → copy the Bot User OAuth Token
`connections:write` 这个 scope 才是让它成为 app-level token(而不是 bot token)的东西。如果 Slack 没给你 Socket Mode 选项,通常就是缺这个 scope。
{
channels: {
slack: {
mode: "socket",
appToken: { source: "env", id: "SLACK_APP_TOKEN" },
botToken: { source: "env", id: "SLACK_BOT_TOKEN" },
},
},
}两个都用 SecretRef。Slack 的 token 是纯 bearer 凭据、不绑 IP,泄露之后在你轮换之前任何人都能用——别放进配置文件。
# Minimum bot scopes: # app_mentions:read channels:history channels:read # chat:write commands groups:history # groups:read im:history im:read # users:read
这个清单是下限而不是建议。特别是缺了 `channels:history`,会得到一个能发不能读的机器人;表现出来像是 Agent 无视上下文,而不像权限问题。
openclaw config patch --file ./slack.socket.json5 openclaw gateway restart openclaw gateway status
真正该看的是 `gateway status`。app-level token 配错会在连接阶段失败,而这个失败只在这里看得到,Slack 那边什么都不显示。
HTTP 模式,以及那个人人都会踩的 ID 坑
如果你确定需要 HTTP 模式,配置有两处不同:用 signing secret 取代 app-level token,并且 Slack 需要一个它真的能访问到的 URL。再往下的行为完全一致。
{
channels: {
slack: {
mode: "http",
botToken: { source: "env", id: "SLACK_BOT_TOKEN" },
signingSecret: { source: "env", id: "SLACK_SIGNING_SECRET" },
webhookPath: "/slack/events",
},
},
}signing secret 是你用来验证请求确实来自 Slack 的东西。不做验证的话,你的 webhook 路径就是一个无鉴权、却能指挥 Agent 的端点——跳过这一步等同于把网关直接敞开。
# Channel allowlists are keyed by Slack ID, never by name. # Right-click a channel → View channel details → the ID is at the bottom. # # "C12345678" correct # "#engineering" silently matches nothing
用 `#名字` 做键不会报错,它只是匹配不到任何东西——于是 Agent 恰好在你想启用的那个频道里保持沉默。这是 Slack 配置中最常见的一个错误。
在接进共享工作区之前值得先想清楚
- ✗一个拥有 channels:history 的机器人,能读到所在频道里发过的一切,包括在任何人想到这个 Agent 之前很久发的消息。
- ✗私信配对默认需要批准。把 dmPolicy 设成 "open" 并配上 allowFrom: ["*"],意味着工作区里任何人都获得了一条通往「能执行命令的 Agent」的私密通道。
- ✗Slack 工作区里通常装着别人的数据。「自托管所以隐私」这句话,在 Agent 开始读共享频道的那一刻就不再成立了。
- ✗群组私信默认关闭,需要设置 dm.groupEnabled——在你断定集成坏了之前,值得先知道这一点。