Slack-бот на базе OpenClaw — это не просто чатбот с заготовленными ответами. Это полноценный агент который выполняет задачи прямо из Slack: ищет информацию в базе данных, создаёт задачи в Jira, пишет отчёты в Notion.
Архитектура интеграции
Slack (пользователь пишет)
↓
Slack Events API (webhook)
↓
Ваш Node.js сервер (обработчик событий)
↓
OpenClaw (выполняет задачу)
↓
Slack API (отправляет ответ обратно)
Настройка Slack App
1. Создайте приложение:
- Откройте api.slack.com → Create App → From scratch
- Имя: “OpenClaw Bot”, workspace: ваш
2. Настройте Bot Token Scopes (OAuth & Permissions):
channels:read
chat:write
app_mentions:read
files:read
users:read
3. Включите Event Subscriptions:
- Request URL:
https://your-server.com/slack/events - Subscribe to bot events:
app_mention,message.im
4. Скопируйте токены:
- Bot User OAuth Token (
xoxb-...) - Signing Secret
Сервер-обработчик
npm init -y
npm install @slack/bolt @slack/web-api dotenv
// src/slack-server.ts
import { App } from "@slack/bolt";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
socketMode: true, // или HTTP для production
appToken: process.env.SLACK_APP_TOKEN,
});
// Обработка упоминания бота (@openclaw-bot что-то сделай)
app.event("app_mention", async ({ event, client, say }) => {
const userId = event.user;
const text = event.text.replace(/<@[A-Z0-9]+>/g, "").trim(); // убираем @упоминание
// Сообщаем что обрабатываем
const thinkingMsg = await say({
text: "⏳ Думаю...",
thread_ts: event.ts,
});
try {
// Вызываем OpenClaw с задачей
const result = await runOpenClaw(text, userId);
// Удаляем "Думаю..." и отвечаем
await client.chat.update({
channel: event.channel,
ts: thinkingMsg.ts as string,
text: result,
});
} catch (error) {
await client.chat.update({
channel: event.channel,
ts: thinkingMsg.ts as string,
text: `❌ Ошибка: ${error instanceof Error ? error.message : "Неизвестная ошибка"}`,
});
}
});
// Прямые сообщения боту
app.message(async ({ message, say }) => {
if (message.subtype || !("text" in message)) return;
const result = await runOpenClaw(message.text ?? "", message.user ?? "");
await say(result);
});
async function runOpenClaw(task: string, userId: string): Promise<string> {
// Запускаем OpenClaw в non-interactive режиме с задачей
const { stdout, stderr } = await execAsync(
`openclaw --no-interactive --output json --prompt ${JSON.stringify(task)}`,
{
env: {
...process.env,
OPENCLAW_USER: userId,
},
timeout: 120000, // 2 минуты максимум
}
);
const result = JSON.parse(stdout);
return result.response || "Задача выполнена";
}
(async () => {
await app.start(3000);
console.log("⚡️ OpenClaw Slack bot is running!");
})();
MCP-сервер для отправки в Slack
Чтобы OpenClaw мог сам инициировать сообщения в Slack:
// mcp-slack/src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { WebClient } from "@slack/web-api";
const slack = new WebClient(process.env.SLACK_BOT_TOKEN);
const server = new Server(
{ name: "slack-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "send_message",
description: "Отправить сообщение в Slack канал или пользователю",
inputSchema: {
type: "object",
properties: {
channel: { type: "string", description: "#channel-name или @username или channel_id" },
text: { type: "string", description: "Текст сообщения (поддерживает Markdown)" },
thread_ts: { type: "string", description: "Timestamp родительского сообщения для ответа в тред" },
},
required: ["channel", "text"],
},
},
{
name: "get_channel_history",
description: "Получить последние сообщения канала",
inputSchema: {
type: "object",
properties: {
channel: { type: "string" },
limit: { type: "number", default: 20 },
},
required: ["channel"],
},
},
{
name: "create_reminder",
description: "Создать напоминание для пользователя",
inputSchema: {
type: "object",
properties: {
user: { type: "string" },
text: { type: "string" },
time: { type: "string", description: "Unix timestamp или 'tomorrow', 'in 2 hours'" },
},
required: ["user", "text", "time"],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params as { name: string; arguments: Record<string, unknown> };
if (name === "send_message") {
const { channel, text, thread_ts } = args as { channel: string; text: string; thread_ts?: string };
await slack.chat.postMessage({ channel, text, thread_ts });
return { content: [{ type: "text", text: "Message sent" }] };
}
if (name === "get_channel_history") {
const { channel, limit = 20 } = args as { channel: string; limit?: number };
const result = await slack.conversations.history({ channel, limit });
return { content: [{ type: "text", text: JSON.stringify(result.messages, null, 2) }] };
}
throw new Error("Unknown tool");
});
const transport = new StdioServerTransport();
await server.connect(transport);
Примеры использования
Ежедневный standup-дайджест
> Каждый день в 9:00 в канале #standup:
1. Собери из GitHub: какие PR смержены за вчера, какие открыты
2. Из Jira: что переехало в Done
3. Из Notion: задачи со статусом "Blocked"
4. Отправь summary в #standup
Формат:
✅ Завершено: [список]
🔄 В работе: [список]
🔴 Блокеры: [список]
Бот-помощник в #support канале
> Ты — первая линия поддержки в Slack-канале #support.
База знаний: Notion workspace (раздел "FAQ").
На каждое сообщение в канале:
1. Если вопрос есть в FAQ — отвечай в тред
2. Если нужна эскалация — добавляй реакцию 🔔 и тегай @support-team
3. Если решил — добавляй ✅
Не отвечай на сообщения уже помеченные ✅.
Деплой-уведомления
> После каждого успешного деплоя в production (GitHub Actions webhook):
1. Отправь в #deployments: что задеплоено, кто, когда
2. Если деплой упал — немедленно в #alerts с @channel
3. Через 5 минут после деплоя: проверь error rate в Datadog,
если вырос > 2% — уведоми в #alerts
Команды через Slash Commands
Настройте slash commands в Slack App:
/report weekly → агент генерирует недельный отчёт
/query "SQL" → агент выполняет запрос к БД и возвращает результат
/remind @user "текст" "через 2 часа" → создаёт напоминание
/status → статус всех сервисов
Безопасность
Верификация запросов: всегда проверяйте Slack Signing Secret. Запрос без валидной подписи отклоняйте.
Права пользователей: не все должны иметь доступ ко всем командам. Проверяйте user_id или roles:
const ADMIN_USERS = ["U1234567", "U7654321"];
app.command("/query", async ({ command, ack, say }) => {
await ack();
if (!ADMIN_USERS.includes(command.user_id)) {
await say("❌ Нет доступа к этой команде");
return;
}
// выполняем команду
});
Логирование: все команды агенту через Slack должны логироваться с user_id и timestamp.
Итог
Slack-бот на OpenClaw — это не автоответчик, а полноценный AI-член команды в чате. Он выполняет задачи по запросу, отправляет проактивные уведомления и интегрируется с вашим tech stack. Начните с простых алертов и ежедневного дайджеста — это быстрый win с первого дня.
Читайте также: Telegram-интеграция и Notion-интеграция.