Mattermost (plugin)
Status: suportado via plugin (token de bot + eventos WebSocket). Canais, grupos e DMs são suportados. O Mattermost é uma plataforma de mensagens para equipes auto-hospedável; consulte o site oficial em mattermost.com para detalhes do produto e downloads.
Plugin necessário
O Mattermost é distribuído como plugin e não vem incluído na instalação principal.
Instale via CLI (registro npm):
openclaw plugins install @openclaw/mattermost
Checkout local (ao executar de um repositório git):
openclaw plugins install ./extensions/mattermost
Se você escolher o Mattermost durante a configuração/onboarding e um checkout git for detectado, o OpenClaw oferecerá o caminho de instalação local automaticamente.
Detalhes: Plugins
Configuração rápida
- Instale o plugin do Mattermost.
- Crie uma conta de bot no Mattermost e copie o token do bot.
- Copie a URL base do Mattermost (ex.:
https://chat.example.com). - Configure o OpenClaw e inicie o gateway.
Configuração mínima:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
Comandos slash nativos
Comandos slash nativos são opt-in. Quando ativados, o OpenClaw registra comandos slash oc_* via
API do Mattermost e recebe POSTs de callback no servidor HTTP do gateway.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Use quando o Mattermost não consegue acessar o gateway diretamente (proxy reverso/URL pública).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
Observações:
native: "auto"tem como padrão desativado para o Mattermost. Definanative: truepara ativar.- Se
callbackUrlfor omitido, o OpenClaw deriva um a partir de host/porta do gateway +callbackPath. - Para configurações multiconta,
commandspode ser definido no nível superior ou emchannels.mattermost.accounts.<id>.commands(valores da conta sobrescrevem campos de nível superior). - Callbacks de comando são validados com tokens por comando e falham fechados quando a verificação de token falha.
- Requisito de acessibilidade: o endpoint de callback deve ser acessível pelo servidor Mattermost.
- Não defina
callbackUrlcomolocalhosta menos que o Mattermost rode no mesmo host/namespace de rede que o OpenClaw. - Não defina
callbackUrlcomo sua URL base do Mattermost a menos que essa URL faça proxy reverso de/api/channels/mattermost/commandpara o OpenClaw. - Uma verificação rápida é
curl https://<gateway-host>/api/channels/mattermost/command; um GET deve retornar405 Method Not Alloweddo OpenClaw, não404.
- Não defina
- Requisito de egress allowlist do Mattermost:
- Se seu callback aponta para endereços privados/tailnet/internos, defina
ServiceSettings.AllowedUntrustedInternalConnectionsdo Mattermost para incluir o host/domínio do callback. - Use entradas de host/domínio, não URLs completas.
- Correto:
gateway.tailnet-name.ts.net - Incorreto:
https://gateway.tailnet-name.ts.net
- Correto:
- Se seu callback aponta para endereços privados/tailnet/internos, defina
Variáveis de ambiente (conta padrão)
Defina estas no host do gateway se preferir variáveis de ambiente:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
Variáveis de ambiente se aplicam apenas à conta padrão (default). Outras contas devem usar valores de configuração.
Modos de chat
O Mattermost responde a DMs automaticamente. O comportamento em canais é controlado por chatmode:
oncall(padrão): responder apenas quando @mencionado em canais.onmessage: responder a todas as mensagens em canais.onchar: responder quando uma mensagem começa com um prefixo gatilho.
Exemplo de configuração:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
Observações:
oncharainda responde a @menções explícitas.channels.mattermost.requireMentioné respeitado para configs legadas, maschatmodeé preferido.
Threading e sessões
Use channels.mattermost.replyToMode para controlar se as respostas em canais e grupos ficam no
canal principal ou iniciam uma thread sob o post de acionamento.
off(padrão): só responde em thread quando o post de entrada já está em uma.first: para posts de nível superior em canais/grupos, inicia uma thread sob esse post e roteia a conversa para uma sessão com escopo de thread.all: mesmo comportamento quefirstpara o Mattermost atualmente.- Mensagens diretas ignoram essa configuração e permanecem sem threading.
Exemplo de configuração:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
Observações:
- Sessões com escopo de thread usam o ID do post de acionamento como raiz da thread.
firsteallsão atualmente equivalentes porque, uma vez que o Mattermost tem uma raiz de thread, os chunks subsequentes e mídias continuam nessa mesma thread.
Controle de acesso (DMs)
- Padrão:
channels.mattermost.dmPolicy = "pairing"(remetentes desconhecidos recebem um código de pareamento). - Aprove via:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- DMs públicas:
channels.mattermost.dmPolicy="open"maischannels.mattermost.allowFrom=["*"].
Canais (grupos)
- Padrão:
channels.mattermost.groupPolicy = "allowlist"(filtrado por menção). - Permita remetentes com
channels.mattermost.groupAllowFrom(IDs de usuário recomendados). - Correspondência por
@usernameé mutável e só é ativada quandochannels.mattermost.dangerouslyAllowNameMatching: true. - Canais abertos:
channels.mattermost.groupPolicy="open"(filtrado por menção). - Observação de runtime: se
channels.mattermostestiver completamente ausente, o runtime recorre agroupPolicy="allowlist"para verificações de grupo (mesmo quechannels.defaults.groupPolicyesteja definido).
Alvos para entrega de saída
Use estes formatos de alvo com openclaw message send ou cron/webhooks:
channel:<id>para um canaluser:<id>para uma DM@usernamepara uma DM (resolvido via API do Mattermost)
IDs opacos soltos (como 64ifufp...) são ambíguos no Mattermost (ID de usuário vs ID de canal).
O OpenClaw os resolve priorizando usuário:
- Se o ID existir como usuário (
GET /api/v4/users/<id>retorna sucesso), o OpenClaw envia uma DM resolvendo o canal direto via/api/v4/channels/direct. - Caso contrário, o ID é tratado como ID de canal.
Se precisar de comportamento determinístico, sempre use os prefixos explícitos (user:<id> / channel:<id>).
Reações (ferramenta de mensagem)
- Use
message action=reactcomchannel=mattermost. messageIdé o ID do post no Mattermost.emojiaceita nomes comothumbsupou:+1:(dois pontos são opcionais).- Defina
remove=true(booleano) para remover uma reação. - Eventos de adicionar/remover reação são encaminhados como eventos de sistema para a sessão roteada do agente.
Exemplos:
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
Config:
channels.mattermost.actions.reactions: ativar/desativar ações de reação (padrão true).- Override por conta:
channels.mattermost.accounts.<id>.actions.reactions.
Botões interativos (ferramenta de mensagem)
Envie mensagens com botões clicáveis. Quando um usuário clica em um botão, o agente recebe a seleção e pode responder.
Ative botões adicionando inlineButtons às capacidades do canal:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
Use message action=send com um parâmetro buttons. Botões são um array 2D (linhas de botões):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
Campos do botão:
text(obrigatório): rótulo de exibição.callback_data(obrigatório): valor enviado de volta ao clicar (usado como ID da ação).style(opcional):"default","primary"ou"danger".
Quando um usuário clica em um botão:
- Todos os botões são substituídos por uma linha de confirmação (ex.: ”✓ Yes selected by @user”).
- O agente recebe a seleção como mensagem de entrada e responde.
Observações:
- Callbacks de botão usam verificação HMAC-SHA256 (automática, sem configuração necessária).
- O Mattermost remove os dados de callback de suas respostas de API (recurso de segurança), então todos os botões são removidos ao clicar — remoção parcial não é possível.
- IDs de ação contendo hífens ou underscores são sanitizados automaticamente (limitação de roteamento do Mattermost).
Config:
channels.mattermost.capabilities: array de strings de capacidade. Adicione"inlineButtons"para ativar a descrição da ferramenta de botões no prompt de sistema do agente.channels.mattermost.interactions.callbackBaseUrl: URL base externa opcional para callbacks de botão (por exemplohttps://gateway.example.com). Use quando o Mattermost não consegue acessar o gateway no seu host de bind diretamente.- Em configurações multiconta, você também pode definir o mesmo campo em
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl. - Se
interactions.callbackBaseUrlfor omitido, o OpenClaw deriva a URL de callback degateway.customBindHost+gateway.port, depois recorre ahttp://localhost:<port>. - Regra de acessibilidade: a URL de callback do botão deve ser acessível pelo servidor Mattermost.
localhostsó funciona quando Mattermost e OpenClaw rodam no mesmo host/namespace de rede. - Se seu alvo de callback é privado/tailnet/interno, adicione seu host/domínio ao
ServiceSettings.AllowedUntrustedInternalConnectionsdo Mattermost.
Integração direta com API (scripts externos)
Scripts externos e webhooks podem postar botões diretamente via API REST do Mattermost
em vez de passar pela ferramenta message do agente. Use buildButtonAttachments() da
extensão quando possível; se postar JSON bruto, siga estas regras:
Estrutura do payload:
{
channel_id: "<channelId>",
message: "Choose an option:",
props: {
attachments: [
{
actions: [
{
id: "mybutton01", // alphanumeric only — see below
type: "button", // required, or clicks are silently ignored
name: "Approve", // display label
style: "primary", // optional: "default", "primary", "danger"
integration: {
url: "https://gateway.example.com/mattermost/interactions/default",
context: {
action_id: "mybutton01", // must match button id (for name lookup)
action: "approve",
// ... any custom fields ...
_token: "<hmac>", // see HMAC section below
},
},
},
],
},
],
},
}
Regras críticas:
- Attachments vão em
props.attachments, não emattachmentsde nível superior (ignorado silenciosamente). - Toda ação precisa de
type: "button"— sem isso, cliques são engolidos silenciosamente. - Toda ação precisa de um campo
id— o Mattermost ignora ações sem IDs. - O
idda ação deve ser apenas alfanumérico ([a-zA-Z0-9]). Hífens e underscores quebram o roteamento de ações do lado do servidor do Mattermost (retorna 404). Remova-os antes de usar. context.action_iddeve corresponder aoiddo botão para que a mensagem de confirmação mostre o nome do botão (ex.: “Approve”) em vez de um ID bruto.context.action_idé obrigatório — o handler de interação retorna 400 sem ele.
Geração de token HMAC:
O gateway verifica cliques de botão com HMAC-SHA256. Scripts externos devem gerar tokens que correspondam à lógica de verificação do gateway:
- Derive o segredo do token do bot:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - Construa o objeto de contexto com todos os campos exceto
_token. - Serialize com chaves ordenadas e sem espaços (o gateway usa
JSON.stringifycom chaves ordenadas, que produz saída compacta). - Assine:
HMAC-SHA256(key=secret, data=serializedContext) - Adicione o digest hex resultante como
_tokenno contexto.
Exemplo em 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}
Armadilhas comuns de HMAC:
- O
json.dumpsdo Python adiciona espaços por padrão ({"key": "val"}). Useseparators=(",", ":")para corresponder à saída compacta do JavaScript ({"key":"val"}). - Sempre assine todos os campos de contexto (menos
_token). O gateway remove_tokene assina tudo que resta. Assinar um subconjunto causa falha de verificação silenciosa. - Use
sort_keys=True— o gateway ordena as chaves antes de assinar, e o Mattermost pode reordenar campos de contexto ao armazenar o payload. - Derive o segredo do token do bot (determinístico), não de bytes aleatórios. O segredo deve ser o mesmo entre o processo que cria botões e o gateway que verifica.
Adaptador de diretório
O plugin do Mattermost inclui um adaptador de diretório que resolve nomes de canais e usuários
via API do Mattermost. Isso permite alvos #channel-name e @username em
openclaw message send e entregas por cron/webhook.
Nenhuma configuração é necessária — o adaptador usa o token do bot da configuração da conta.
Multiconta
O Mattermost suporta múltiplas contas em 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" },
},
},
},
}
Solução de problemas
- Sem respostas em canais: verifique se o bot está no canal e mencione-o (oncall), use um prefixo gatilho (onchar) ou defina
chatmode: "onmessage". - Erros de autenticação: verifique o token do bot, a URL base e se a conta está ativada.
- Problemas multiconta: variáveis de ambiente se aplicam apenas à conta
default. - Botões aparecem como caixas brancas: o agente pode estar enviando dados de botão malformados. Verifique se cada botão tem ambos os campos
textecallback_data. - Botões renderizam mas cliques não fazem nada: verifique se
AllowedUntrustedInternalConnectionsna configuração do servidor Mattermost inclui127.0.0.1 localhost, e queEnablePostActionIntegrationétrueem ServiceSettings. - Botões retornam 404 ao clicar: o
iddo botão provavelmente contém hífens ou underscores. O roteador de ações do Mattermost quebra com IDs não alfanuméricos. Use apenas[a-zA-Z0-9]. - Gateway registra
invalid _token: incompatibilidade de HMAC. Verifique se você assina todos os campos de contexto (não um subconjunto), usa chaves ordenadas e usa JSON compacto (sem espaços). Veja a seção de HMAC acima. - Gateway registra
missing _token in context: o campo_tokennão está no contexto do botão. Certifique-se de que está incluído ao construir o payload de integração. - Confirmação mostra ID bruto em vez do nome do botão:
context.action_idnão corresponde aoiddo botão. Defina ambos com o mesmo valor sanitizado. - Agente não sabe sobre botões: adicione
capabilities: ["inlineButtons"]à configuração do canal Mattermost.