Mattermost (плагин)
Статус: поддерживается через плагин (токен бота + события WebSocket). Каналы, группы и ЛС поддерживаются. Mattermost — самохостируемая платформа командного обмена сообщениями; подробнее на mattermost.com.
Требуется плагин
Mattermost поставляется как плагин и не входит в базовую установку.
Установка через CLI (npm-реестр):
openclaw plugins install @openclaw/mattermost
Из локальной копии (при работе из git-репозитория):
openclaw plugins install ./extensions/mattermost
Если вы выбираете Mattermost при настройке/онбординге и обнаружена git-копия, OpenClaw автоматически предложит локальную установку.
Подробнее: Плагины
Быстрая настройка
- Установите плагин Mattermost.
- Создайте аккаунт бота Mattermost и скопируйте токен бота.
- Скопируйте базовый URL Mattermost (например,
https://chat.example.com). - Настройте OpenClaw и запустите шлюз.
Минимальная конфигурация:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
Нативные slash-команды
Нативные slash-команды включаются по желанию. При включении OpenClaw регистрирует slash-команды oc_* через Mattermost API и получает callback POST на HTTP-сервер шлюза.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Используйте, когда Mattermost не может напрямую связаться со шлюзом (reverse proxy/публичный URL).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
Примечания:
native: "auto"по умолчанию отключён для Mattermost. Задайтеnative: trueдля включения.- Если
callbackUrlне задан, OpenClaw определяет его из host/port шлюза +callbackPath. - Для мульти-аккаунтных конфигураций
commandsможно задать на верхнем уровне или подchannels.mattermost.accounts.<id>.commands(значения аккаунта переопределяют верхнеуровневые). - Callback’и команд проверяются по токенам для каждой команды и отклоняются при несовпадении.
- Требование доступности: эндпоинт callback’а должен быть доступен с сервера Mattermost.
- Не задавайте
callbackUrlкакlocalhost, если Mattermost не работает на том же хосте/сетевом пространстве имён, что и OpenClaw. - Не задавайте
callbackUrlкак URL Mattermost, если этот URL не проксирует/api/channels/mattermost/commandна OpenClaw. - Быстрая проверка:
curl https://<gateway-host>/api/channels/mattermost/command; GET должен вернуть405 Method Not Allowedот OpenClaw, а не404.
- Не задавайте
- Требование белого списка исходящих соединений Mattermost:
- Если callback указывает на приватные/tailnet/внутренние адреса, задайте
ServiceSettings.AllowedUntrustedInternalConnectionsв Mattermost, включив хост/домен callback’а. - Используйте записи хост/домен, не полные URL.
- Правильно:
gateway.tailnet-name.ts.net - Неправильно:
https://gateway.tailnet-name.ts.net
- Правильно:
- Если callback указывает на приватные/tailnet/внутренние адреса, задайте
Переменные окружения (аккаунт по умолчанию)
Задайте на хосте шлюза, если предпочитаете env:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
Env применяются только к аккаунту по умолчанию (default). Другие аккаунты должны использовать конфигурацию.
Режимы чата
Mattermost отвечает на ЛС автоматически. Поведение в каналах управляется через chatmode:
oncall(по умолчанию): отвечать только при @упоминании в каналах.onmessage: отвечать на каждое сообщение в канале.onchar: отвечать, когда сообщение начинается с триггерного префикса.
Пример конфигурации:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
Примечания:
oncharвсё равно отвечает на явные @упоминания.channels.mattermost.requireMentionучитывается для устаревших конфигураций, ноchatmodeпредпочтительнее.
Потоки и сессии
Используйте channels.mattermost.replyToMode для управления тем, остаются ли ответы в каналах и группах в основном канале или создают поток под триггерным постом.
off(по умолчанию): отвечать в потоке, только если входящий пост уже в нём.first: для верхнеуровневых постов канала/группы начать поток под этим постом и направить беседу в сессию с областью видимости потока.all: аналогичноfirstдля Mattermost на данный момент.- Прямые сообщения игнорируют эту настройку и остаются без потоков.
Пример конфигурации:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
Примечания:
- Сессии с областью видимости потока используют ID триггерного поста как корень потока.
firstиallв настоящее время эквивалентны, поскольку после создания корня потока Mattermost последующие чанки и медиа продолжают в том же потоке.
Контроль доступа (ЛС)
- По умолчанию:
channels.mattermost.dmPolicy = "pairing"(неизвестные отправители получают код спаривания). - Подтверждение:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- Публичные ЛС:
channels.mattermost.dmPolicy="open"плюсchannels.mattermost.allowFrom=["*"].
Каналы (группы)
- По умолчанию:
channels.mattermost.groupPolicy = "allowlist"(с гейтингом по упоминанию). - Список доступа отправителей через
channels.mattermost.groupAllowFrom(рекомендуются user ID). - Сопоставление
@usernameизменяемо и включено только приchannels.mattermost.dangerouslyAllowNameMatching: true. - Открытые каналы:
channels.mattermost.groupPolicy="open"(с гейтингом по упоминанию). - Примечание: если
channels.mattermostполностью отсутствует, runtime использует fallback кgroupPolicy="allowlist"для групповых проверок (даже если заданchannels.defaults.groupPolicy).
Цели исходящей доставки
Используйте эти форматы целей с openclaw message send или cron/вебхуками:
channel:<id>для каналаuser:<id>для ЛС@usernameдля ЛС (разрешается через Mattermost API)
Голые непрозрачные ID (вроде 64ifufp...) неоднозначны в Mattermost (user ID vs channel ID).
OpenClaw разрешает их сначала как пользователя:
- Если ID существует как пользователь (
GET /api/v4/users/<id>успешен), OpenClaw отправляет ЛС, разрешая прямой канал через/api/v4/channels/direct. - Иначе ID считается ID канала.
Для детерминированного поведения всегда используйте явные префиксы (user:<id> / channel:<id>).
Реакции (инструмент message)
- Используйте
message action=reactсchannel=mattermost. messageId— ID поста Mattermost.emojiпринимает имена вродеthumbsupили:+1:(двоеточия необязательны).- Задайте
remove=true(boolean) для удаления реакции. - События добавления/удаления реакций пересылаются как системные события в маршрутизированную сессию агента.
Примеры:
message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup
message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup remove=true
Конфигурация:
channels.mattermost.actions.reactions: включение/выключение действий реакций (по умолчанию true).- Переопределение по аккаунту:
channels.mattermost.accounts.<id>.actions.reactions.
Интерактивные кнопки (инструмент message)
Отправка сообщений с кликабельными кнопками. Когда пользователь нажимает кнопку, агент получает выбор и может ответить.
Включите кнопки, добавив inlineButtons в возможности канала:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
Используйте message action=send с параметром buttons. Кнопки — двумерный массив (ряды кнопок):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
Поля кнопок:
text(обязательно): отображаемая метка.callback_data(обязательно): значение, возвращаемое при клике (используется как ID действия).style(необязательно):"default","primary"или"danger".
При клике:
- Все кнопки заменяются строкой подтверждения (например, «Yes selected by @user»).
- Агент получает выбор как входящее сообщение и отвечает.
Примечания:
- Callback’и кнопок используют HMAC-SHA256 верификацию (автоматически, без конфигурации).
- Mattermost удаляет callback data из ответов API (функция безопасности), поэтому все кнопки удаляются при клике — частичное удаление невозможно.
- ID действий, содержащие дефисы или подчёркивания, автоматически санитизируются (ограничение маршрутизации Mattermost).
Конфигурация:
channels.mattermost.capabilities: массив строк возможностей. Добавьте"inlineButtons"для включения описания инструмента кнопок в системном промпте агента.channels.mattermost.interactions.callbackBaseUrl: необязательный внешний базовый URL для callback’ов кнопок (напримерhttps://gateway.example.com). Используйте, когда Mattermost не может напрямую связаться со шлюзом по его bind host.- В мульти-аккаунтных конфигурациях то же поле можно задать под
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl. - Если
interactions.callbackBaseUrlне задан, OpenClaw определяет callback URL изgateway.customBindHost+gateway.port, затем fallback кhttp://localhost:<port>. - Правило доступности: callback URL кнопок должен быть доступен с сервера Mattermost.
localhostработает, только когда Mattermost и OpenClaw на одном хосте/сетевом пространстве имён. - Если callback указывает на приватный/tailnet/внутренний адрес, добавьте его хост/домен в
ServiceSettings.AllowedUntrustedInternalConnectionsMattermost.
Прямая интеграция API (внешние скрипты)
Внешние скрипты и вебхуки могут отправлять кнопки напрямую через Mattermost REST API вместо инструмента message агента. Используйте buildButtonAttachments() из расширения при возможности; при отправке сырого JSON следуйте этим правилам:
Структура полезной нагрузки:
{
channel_id: "<channelId>",
message: "Choose an option:",
props: {
attachments: [
{
actions: [
{
id: "mybutton01", // только алфавитно-цифровые — см. ниже
type: "button", // обязательно, иначе клики молча игнорируются
name: "Approve", // отображаемая метка
style: "primary", // необязательно: "default", "primary", "danger"
integration: {
url: "https://gateway.example.com/mattermost/interactions/default",
context: {
action_id: "mybutton01", // должен совпадать с id кнопки (для поиска имени)
action: "approve",
// ... любые пользовательские поля ...
_token: "<hmac>", // см. раздел HMAC ниже
},
},
},
],
},
],
},
}
Критические правила:
- Attachments размещаются в
props.attachments, не верхнеуровневомattachments(молча игнорируются). - Каждому действию нужен
type: "button"— без него клики поглощаются молча. - Каждому действию нужно поле
id— Mattermost игнорирует действия без ID. idдействия должен быть только алфавитно-цифровым ([a-zA-Z0-9]). Дефисы и подчёркивания ломают серверную маршрутизацию действий Mattermost (возвращает 404). Удаляйте их.context.action_idдолжен совпадать сidкнопки, чтобы подтверждающее сообщение показывало имя кнопки (например, «Approve») вместо сырого ID.context.action_idобязателен — обработчик взаимодействий возвращает 400 без него.
Генерация HMAC-токена:
Шлюз проверяет клики кнопок через HMAC-SHA256. Внешние скрипты должны генерировать токены, соответствующие логике верификации шлюза:
- Получите секрет из токена бота:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - Постройте объект context со всеми полями кроме
_token. - Сериализуйте с отсортированными ключами и без пробелов (шлюз использует
JSON.stringifyс отсортированными ключами, что даёт компактный вывод). - Подпишите:
HMAC-SHA256(key=secret, data=serializedContext) - Добавьте полученный hex-дайджест как
_tokenв context.
Пример на Python:
import hmac, hashlib, json
secret = hmac.new(
b"openclaw-mattermost-interactions",
bot_token.encode(), hashlib.sha256
).hexdigest()
ctx = {"action_id": "mybutton01", "action": "approve"}
payload = json.dumps(ctx, sort_keys=True, separators=(",", ":"))
token = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
context = {**ctx, "_token": token}
Частые ошибки HMAC:
json.dumpsPython добавляет пробелы по умолчанию ({"key": "val"}). Используйтеseparators=(",", ":")для соответствия компактному выводу JavaScript ({"key":"val"}).- Всегда подписывайте все поля context (минус
_token). Шлюз удаляет_token, затем подписывает всё остальное. Подпись подмножества приводит к молчаливому провалу верификации. - Используйте
sort_keys=True— шлюз сортирует ключи перед подписью, а Mattermost может переупорядочить поля context при хранении. - Получайте секрет из токена бота (детерминированно), а не случайных байтов. Секрет должен быть одинаковым в процессе, создающем кнопки, и шлюзе, верифицирующем их.
Адаптер каталога
Плагин Mattermost включает адаптер каталога, разрешающий имена каналов и пользователей через Mattermost API. Это позволяет использовать цели #channel-name и @username в openclaw message send и доставках cron/вебхуков.
Конфигурация не требуется — адаптер использует токен бота из конфигурации аккаунта.
Мульти-аккаунт
Mattermost поддерживает несколько аккаунтов через channels.mattermost.accounts:
{
channels: {
mattermost: {
accounts: {
default: { name: "Primary", botToken: "mm-token", baseUrl: "https://chat.example.com" },
alerts: { name: "Alerts", botToken: "mm-token-2", baseUrl: "https://alerts.example.com" },
},
},
},
}
Устранение неполадок
- Нет ответов в каналах: убедитесь, что бот в канале и упомяните его (oncall), используйте триггерный префикс (onchar), или задайте
chatmode: "onmessage". - Ошибки аутентификации: проверьте токен бота, базовый URL и включён ли аккаунт.
- Проблемы мульти-аккаунта: env применяются только к аккаунту
default. - Кнопки отображаются как белые блоки: агент может отправлять некорректные данные кнопок. Проверьте, что каждая кнопка имеет поля
textиcallback_data. - Кнопки рендерятся, но клики ничего не делают: проверьте
AllowedUntrustedInternalConnectionsв конфигурации сервера Mattermost (включает127.0.0.1 localhost) иEnablePostActionIntegrationравноtrueв ServiceSettings. - Кнопки возвращают 404 при клике:
idкнопки вероятно содержит дефисы или подчёркивания. Маршрутизатор действий Mattermost ломается на неалфавитно-цифровых ID. Используйте только[a-zA-Z0-9]. - Логи шлюза
invalid _token: несовпадение HMAC. Проверьте, что подписываете все поля context (не подмножество), используете отсортированные ключи и компактный JSON (без пробелов). См. раздел HMAC выше. - Логи шлюза
missing _token in context: поле_tokenотсутствует в context кнопки. Убедитесь, что оно включено при формировании полезной нагрузки интеграции. - Подтверждение показывает сырой ID вместо имени кнопки:
context.action_idне совпадает сidкнопки. Задайте оба одинаковым санитизированным значением. - Агент не знает о кнопках: добавьте
capabilities: ["inlineButtons"]в конфигурацию канала Mattermost.