Mattermost (plugin)
Estado: compatible vía plugin (token del bot + eventos WebSocket). Canales, grupos y mensajes directos son compatibles. Mattermost es una plataforma de mensajería de equipo auto-hospedable; consulta el sitio oficial en mattermost.com para más detalles y descargas.
Plugin obligatorio
Mattermost se distribuye como plugin y no viene incluido en la instalación base.
Instalación por CLI (registro npm):
openclaw plugins install @openclaw/mattermost
Checkout local (cuando se ejecuta desde un repositorio git):
openclaw plugins install ./extensions/mattermost
Si eliges Mattermost durante la configuración/onboarding y se detecta un checkout de git, OpenClaw ofrecerá la ruta de instalación local automáticamente.
Detalles: Plugins
Configuración rápida
- Instala el plugin de Mattermost.
- Crea una cuenta de bot en Mattermost y copia el token del bot.
- Copia la URL base de Mattermost (p. ej.,
https://chat.example.com). - Configura OpenClaw e inicia el gateway.
Configuración mínima:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
Comandos slash nativos
Los comandos slash nativos son opcionales. Cuando se activan, OpenClaw registra comandos slash oc_* vía
la API de Mattermost y recibe callbacks POST en el servidor HTTP del gateway.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Usa cuando Mattermost no puede alcanzar el gateway directamente (proxy inverso/URL pública).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
Notas:
native: "auto"está desactivado por defecto para Mattermost. Establecenative: truepara activarlo.- Si se omite
callbackUrl, OpenClaw lo deriva del host/puerto del gateway +callbackPath. - Para configuraciones multicuenta,
commandspuede establecerse a nivel superior o bajochannels.mattermost.accounts.<id>.commands(los valores de cuenta sobrescriben los de nivel superior). - Los callbacks de comandos se validan con tokens por comando y fallan de forma cerrada cuando las verificaciones de token fallan.
- Requisito de alcanzabilidad: el endpoint de callback debe ser alcanzable desde el servidor Mattermost.
- No establezcas
callbackUrlalocalhosta menos que Mattermost se ejecute en el mismo host/espacio de red que OpenClaw. - No establezcas
callbackUrla tu URL base de Mattermost a menos que esa URL haga proxy inverso de/api/channels/mattermost/commandhacia OpenClaw. - Una verificación rápida es
curl https://<gateway-host>/api/channels/mattermost/command; un GET debería devolver405 Method Not Allowedde OpenClaw, no404.
- No establezcas
- Requisito de lista de permitidos de egreso de Mattermost:
- Si tu callback apunta a direcciones privadas/tailnet/internas, establece
ServiceSettings.AllowedUntrustedInternalConnectionsde Mattermost para incluir el host/dominio del callback. - Usa entradas de host/dominio, no URLs completas.
- Correcto:
gateway.tailnet-name.ts.net - Incorrecto:
https://gateway.tailnet-name.ts.net
- Correcto:
- Si tu callback apunta a direcciones privadas/tailnet/internas, establece
Variables de entorno (cuenta predeterminada)
Establece estas en el host del gateway si prefieres variables de entorno:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
Las variables de entorno aplican solo a la cuenta predeterminada (default). Otras cuentas deben usar valores de configuración.
Modos de chat
Mattermost responde a mensajes directos automáticamente. El comportamiento en canales se controla con chatmode:
oncall(predeterminado): responde solo cuando se le @menciona en canales.onmessage: responde a todos los mensajes del canal.onchar: responde cuando un mensaje comienza con un prefijo activador.
Ejemplo de configuración:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
Notas:
oncharsigue respondiendo a @menciones explícitas.channels.mattermost.requireMentionse respeta para configuraciones legacy, pero se prefierechatmode.
Hilos y sesiones
Usa channels.mattermost.replyToMode para controlar si las respuestas en canales y grupos permanecen en
el canal principal o inician un hilo bajo el post que activó la respuesta.
off(predeterminado): solo responde en un hilo cuando el post entrante ya está en uno.first: para posts de nivel superior en canales/grupos, inicia un hilo bajo ese post y enruta la conversación a una sesión con alcance de hilo.all: mismo comportamiento quefirstpara Mattermost actualmente.- Los mensajes directos ignoran esta configuración y permanecen sin hilos.
Ejemplo de configuración:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
Notas:
- Las sesiones con alcance de hilo usan el ID del post activador como raíz del hilo.
firstyallson actualmente equivalentes porque una vez que Mattermost tiene una raíz de hilo, los fragmentos y medios de seguimiento continúan en ese mismo hilo.
Control de acceso (mensajes directos)
- Por defecto:
channels.mattermost.dmPolicy = "pairing"(los remitentes desconocidos reciben un código de emparejamiento). - Aprueba mediante:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- Mensajes directos públicos:
channels.mattermost.dmPolicy="open"máschannels.mattermost.allowFrom=["*"].
Canales (grupos)
- Por defecto:
channels.mattermost.groupPolicy = "allowlist"(controlado por mención). - Lista de permitidos de remitentes con
channels.mattermost.groupAllowFrom(se recomiendan IDs de usuario). - La coincidencia por
@usernamees mutable y solo se activa cuandochannels.mattermost.dangerouslyAllowNameMatching: true. - Canales abiertos:
channels.mattermost.groupPolicy="open"(controlado por mención). - Nota de runtime: si
channels.mattermostestá completamente ausente, el runtime recurre agroupPolicy="allowlist"para verificaciones de grupo (incluso sichannels.defaults.groupPolicyestá establecido).
Destinos para entrega saliente
Usa estos formatos de destino con openclaw message send o cron/webhooks:
channel:<id>para un canaluser:<id>para un mensaje directo@usernamepara un mensaje directo (resuelto vía la API de Mattermost)
Los IDs opacos solos (como 64ifufp...) son ambiguos en Mattermost (ID de usuario vs ID de canal).
OpenClaw los resuelve dando prioridad al usuario:
- Si el ID existe como usuario (
GET /api/v4/users/<id>tiene éxito), OpenClaw envía un mensaje directo resolviendo el canal directo vía/api/v4/channels/direct. - De lo contrario, el ID se trata como un ID de canal.
Si necesitas un comportamiento determinístico, usa siempre los prefijos explícitos (user:<id> / channel:<id>).
Reacciones (herramienta de mensaje)
- Usa
message action=reactconchannel=mattermost. messageIdes el ID del post de Mattermost.emojiacepta nombres comothumbsupo:+1:(los dos puntos son opcionales).- Establece
remove=true(booleano) para eliminar una reacción. - Los eventos de añadir/eliminar reacciones se reenvían como eventos del sistema a la sesión del agente enrutado.
Ejemplos:
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
Configuración:
channels.mattermost.actions.reactions: activar/desactivar acciones de reacción (por defecto true).- Excepción por cuenta:
channels.mattermost.accounts.<id>.actions.reactions.
Botones interactivos (herramienta de mensaje)
Envía mensajes con botones clicables. Cuando un usuario hace clic en un botón, el agente recibe la selección y puede responder.
Activa los botones añadiendo inlineButtons a las capacidades del canal:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
Usa message action=send con un parámetro buttons. Los botones son un array 2D (filas de botones):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
Campos de botón:
text(obligatorio): etiqueta a mostrar.callback_data(obligatorio): valor enviado de vuelta al hacer clic (usado como ID de acción).style(opcional):"default","primary"o"danger".
Cuando un usuario hace clic en un botón:
- Todos los botones se reemplazan con una línea de confirmación (p. ej., “Yes seleccionado por @user”).
- El agente recibe la selección como un mensaje entrante y responde.
Notas:
- Los callbacks de botones usan verificación HMAC-SHA256 (automática, sin configuración necesaria).
- Mattermost elimina los datos de callback de sus respuestas de API (función de seguridad), por lo que todos los botones se eliminan al hacer clic — la eliminación parcial no es posible.
- Los IDs de acción que contienen guiones o guiones bajos se sanean automáticamente (limitación de enrutamiento de Mattermost).
Configuración:
channels.mattermost.capabilities: array de cadenas de capacidad. Añade"inlineButtons"para activar la descripción de la herramienta de botones en el prompt del sistema del agente.channels.mattermost.interactions.callbackBaseUrl: URL base externa opcional para callbacks de botones (por ejemplohttps://gateway.example.com). Úsala cuando Mattermost no pueda alcanzar el gateway en su host de enlace directamente.- En configuraciones multicuenta, también puedes establecer el mismo campo bajo
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl. - Si se omite
interactions.callbackBaseUrl, OpenClaw deriva la URL de callback degateway.customBindHost+gateway.port, luego recurre ahttp://localhost:<port>. - Regla de alcanzabilidad: la URL de callback del botón debe ser alcanzable desde el servidor Mattermost.
localhostsolo funciona cuando Mattermost y OpenClaw se ejecutan en el mismo host/espacio de red. - Si tu destino de callback es privado/tailnet/interno, añade su host/dominio a
ServiceSettings.AllowedUntrustedInternalConnectionsde Mattermost.
Integración directa de API (scripts externos)
Los scripts externos y webhooks pueden publicar botones directamente vía la API REST de Mattermost
en lugar de usar la herramienta message del agente. Usa buildButtonAttachments() de
la extensión cuando sea posible; si publicas JSON sin procesar, sigue estas reglas:
Estructura del payload:
{
channel_id: "<channelId>",
message: "Choose an option:",
props: {
attachments: [
{
actions: [
{
id: "mybutton01", // solo alfanumérico — ver abajo
type: "button", // obligatorio, o los clics se ignoran silenciosamente
name: "Approve", // etiqueta a mostrar
style: "primary", // opcional: "default", "primary", "danger"
integration: {
url: "https://gateway.example.com/mattermost/interactions/default",
context: {
action_id: "mybutton01", // debe coincidir con el id del botón (para búsqueda de nombre)
action: "approve",
// ... campos personalizados ...
_token: "<hmac>", // ver sección HMAC abajo
},
},
},
],
},
],
},
}
Reglas críticas:
- Los adjuntos van en
props.attachments, no enattachmentsde nivel superior (ignorado silenciosamente). - Cada acción necesita
type: "button"— sin esto, los clics se pierden silenciosamente. - Cada acción necesita un campo
id— Mattermost ignora acciones sin ID. - El
idde acción debe ser solo alfanumérico ([a-zA-Z0-9]). Los guiones y guiones bajos rompen el enrutamiento de acciones del lado del servidor de Mattermost (devuelve 404). context.action_iddebe coincidir con eliddel botón para que el mensaje de confirmación muestre el nombre del botón (p. ej., “Approve”) en vez de un ID sin procesar.context.action_ides obligatorio — el manejador de interacciones devuelve 400 sin él.
Generación de token HMAC:
El gateway verifica los clics de botón con HMAC-SHA256. Los scripts externos deben generar tokens que coincidan con la lógica de verificación del gateway:
- Deriva el secreto del token del bot:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - Construye el objeto de contexto con todos los campos excepto
_token. - Serializa con claves ordenadas y sin espacios (el gateway usa
JSON.stringifycon claves ordenadas, que produce salida compacta). - Firma:
HMAC-SHA256(key=secret, data=serializedContext) - Añade el digest hexadecimal resultante como
_tokenen el contexto.
Ejemplo en 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}
Errores comunes de HMAC:
json.dumpsde Python añade espacios por defecto ({"key": "val"}). Usaseparators=(",", ":")para coincidir con la salida compacta de JavaScript ({"key":"val"}).- Firma siempre todos los campos del contexto (menos
_token). El gateway elimina_tokeny luego firma todo lo restante. Firmar un subconjunto causa una falla silenciosa de verificación. - Usa
sort_keys=True— el gateway ordena las claves antes de firmar, y Mattermost puede reordenar los campos del contexto al almacenar el payload. - Deriva el secreto del token del bot (determinístico), no de bytes aleatorios. El secreto debe ser el mismo en el proceso que crea botones y el gateway que los verifica.
Adaptador de directorio
El plugin de Mattermost incluye un adaptador de directorio que resuelve nombres de canales y usuarios
vía la API de Mattermost. Esto habilita destinos #channel-name y @username en
openclaw message send y entregas de cron/webhooks.
No se necesita configuración — el adaptador usa el token del bot de la configuración de la cuenta.
Multicuenta
Mattermost admite múltiples cuentas bajo 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" },
},
},
},
}
Solución de problemas
- Sin respuestas en canales: asegúrate de que el bot esté en el canal y menciónalo (oncall), usa un prefijo activador (onchar) o establece
chatmode: "onmessage". - Errores de autenticación: verifica el token del bot, la URL base y si la cuenta está activada.
- Problemas multicuenta: las variables de entorno solo aplican a la cuenta
default. - Los botones aparecen como cajas blancas: el agente puede estar enviando datos de botón malformados. Verifica que cada botón tenga los campos
textycallback_data. - Los botones se muestran pero los clics no hacen nada: verifica que
AllowedUntrustedInternalConnectionsen la configuración del servidor Mattermost incluya127.0.0.1 localhost, y queEnablePostActionIntegrationseatrueen ServiceSettings. - Los botones devuelven 404 al hacer clic: el
iddel botón probablemente contiene guiones o guiones bajos. El enrutador de acciones de Mattermost falla con IDs no alfanuméricos. Usa solo[a-zA-Z0-9]. - El gateway registra
invalid _token: discrepancia HMAC. Verifica que firmes todos los campos del contexto (no un subconjunto), uses claves ordenadas y uses JSON compacto (sin espacios). Consulta la sección HMAC arriba. - El gateway registra
missing _token in context: el campo_tokenno está en el contexto del botón. Asegúrate de incluirlo al construir el payload de integración. - La confirmación muestra el ID sin procesar en vez del nombre del botón:
context.action_idno coincide con eliddel botón. Establece ambos con el mismo valor saneado. - El agente no conoce los botones: añade
capabilities: ["inlineButtons"]a la configuración del canal Mattermost.