Mattermost (plugin)
Stato: supportato via plugin (bot token + eventi WebSocket). Canali, gruppi e DM sono supportati. Mattermost e una piattaforma di messaggistica per team auto-ospitabile; visita il sito ufficiale su mattermost.com per dettagli sul prodotto e download.
Plugin necessario
Mattermost e distribuito come plugin e non e incluso nell’installazione core.
Installa da CLI (registro npm):
openclaw plugins install @openclaw/mattermost
Da checkout locale (se stai lavorando da un repo git):
openclaw plugins install ./extensions/mattermost
Se scegli Mattermost durante la configurazione/onboarding e viene rilevato un checkout git, OpenClaw offrira automaticamente il percorso di installazione locale.
Dettagli: Plugin
Setup rapido
- Installa il plugin Mattermost.
- Crea un account bot Mattermost e copia il bot token.
- Copia l’URL base di Mattermost (es.
https://chat.example.com). - Configura OpenClaw e avvia il gateway.
Configurazione minimale:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
Comandi slash nativi
I comandi slash nativi sono opt-in. Quando abilitati, OpenClaw registra comandi slash oc_* tramite
l’API Mattermost e riceve callback POST sul server HTTP del gateway.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Usa quando Mattermost non puo raggiungere il gateway direttamente (reverse proxy/URL pubblico).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
Note:
native: "auto"e disabilitato per impostazione predefinita per Mattermost. Impostanative: trueper abilitare.- Se
callbackUrle omesso, OpenClaw ne deriva uno da host/porta del gateway +callbackPath. - Per configurazioni multi-account,
commandspuo essere impostato a livello superiore o sottochannels.mattermost.accounts.<id>.commands(i valori dell’account sovrascrivono i campi di livello superiore). - I callback dei comandi sono validati con token per comando e si chiudono in modo sicuro quando i controlli sui token falliscono.
- Requisito di raggiungibilita: l’endpoint callback deve essere raggiungibile dal server Mattermost.
- Non impostare
callbackUrlalocalhosta meno che Mattermost non giri sullo stesso host/namespace di rete di OpenClaw. - Non impostare
callbackUrlal tuo URL base Mattermost a meno che quell’URL non faccia reverse proxy di/api/channels/mattermost/commandverso OpenClaw. - Un controllo rapido e
curl https://<gateway-host>/api/channels/mattermost/command; un GET dovrebbe restituire405 Method Not Allowedda OpenClaw, non404.
- Non impostare
- Requisito allowlist egress Mattermost:
- Se il tuo callback punta a indirizzi privati/tailnet/interni, imposta
ServiceSettings.AllowedUntrustedInternalConnectionsdi Mattermost per includere l’host/dominio del callback. - Usa voci host/dominio, non URL completi.
- Corretto:
gateway.tailnet-name.ts.net - Errato:
https://gateway.tailnet-name.ts.net
- Corretto:
- Se il tuo callback punta a indirizzi privati/tailnet/interni, imposta
Variabili d’ambiente (account predefinito)
Impostale sull’host del gateway se preferisci le variabili env:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
Le variabili env si applicano solo all’account predefinito (default). Gli altri account devono usare valori dal config.
Modalita chat
Mattermost risponde ai DM automaticamente. Il comportamento nei canali e controllato da chatmode:
oncall(predefinito): risponde solo quando @menzionato nei canali.onmessage: risponde a ogni messaggio del canale.onchar: risponde quando un messaggio inizia con un prefisso trigger.
Esempio config:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
Note:
oncharrisponde comunque alle @menzioni esplicite.channels.mattermost.requireMentione rispettato per config legacy machatmodee preferito.
Threading e sessioni
Usa channels.mattermost.replyToMode per controllare se le risposte nei canali e gruppi restano nel
canale principale o avviano un thread sotto il post che le ha attivate.
off(predefinito): rispondi in un thread solo quando il post in ingresso e gia in uno.first: per i post top-level di canale/gruppo, avvia un thread sotto quel post e instradata la conversazione a una sessione con ambito thread.all: stesso comportamento difirstper Mattermost oggi.- I messaggi diretti ignorano questa impostazione e restano senza thread.
Esempio config:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
Note:
- Le sessioni con ambito thread usano l’id del post che le ha attivate come root del thread.
firsteallsono attualmente equivalenti perche una volta che Mattermost ha una root del thread, i chunk e i media successivi continuano nello stesso thread.
Controllo degli accessi (DM)
- Predefinito:
channels.mattermost.dmPolicy = "pairing"(i mittenti sconosciuti ricevono un codice di pairing). - Approvazione tramite:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- DM pubblici:
channels.mattermost.dmPolicy="open"piuchannels.mattermost.allowFrom=["*"].
Canali (gruppi)
- Predefinito:
channels.mattermost.groupPolicy = "allowlist"(gating menzione). - Allowlist mittenti con
channels.mattermost.groupAllowFrom(user ID consigliati). - Il matching
@usernamee mutabile e abilitato solo quandochannels.mattermost.dangerouslyAllowNameMatching: true. - Canali aperti:
channels.mattermost.groupPolicy="open"(gating menzione). - Nota runtime: se
channels.mattermoste completamente assente, il runtime torna agroupPolicy="allowlist"per i controlli di gruppo (anche sechannels.defaults.groupPolicye impostato).
Target per consegna in uscita
Usa questi formati target con openclaw message send o cron/webhook:
channel:<id>per un canaleuser:<id>per un DM@usernameper un DM (risolto via API Mattermost)
Gli ID opachi semplici (come 64ifufp...) sono ambigui in Mattermost (user ID vs channel ID).
OpenClaw li risolve utente-prima:
- Se l’ID esiste come utente (
GET /api/v4/users/<id>ha successo), OpenClaw invia un DM risolvendo il canale diretto via/api/v4/channels/direct. - Altrimenti l’ID e trattato come un channel ID.
Se hai bisogno di un comportamento deterministico, usa sempre i prefissi espliciti (user:<id> / channel:<id>).
Reazioni (strumento message)
- Usa
message action=reactconchannel=mattermost. messageIde l’id del post Mattermost.emojiaccetta nomi comethumbsupo:+1:(i due punti sono opzionali).- Imposta
remove=true(booleano) per rimuovere una reazione. - Gli eventi di aggiunta/rimozione reazione sono inoltrati come eventi di sistema alla sessione dell’agent instradato.
Esempi:
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
Configurazione:
channels.mattermost.actions.reactions: abilita/disabilita le azioni di reazione (predefinito true).- Sovrascrittura per account:
channels.mattermost.accounts.<id>.actions.reactions.
Pulsanti interattivi (strumento message)
Invia messaggi con pulsanti cliccabili. Quando un utente clicca un pulsante, l’agent riceve la selezione e puo rispondere.
Abilita i pulsanti aggiungendo inlineButtons alle capabilities del canale:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
Usa message action=send con un parametro buttons. I pulsanti sono un array 2D (righe di pulsanti):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Si","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
Campi dei pulsanti:
text(obbligatorio): etichetta visualizzata.callback_data(obbligatorio): valore inviato al click (usato come action ID).style(opzionale):"default","primary"o"danger".
Quando un utente clicca un pulsante:
- Tutti i pulsanti sono sostituiti con una riga di conferma (es. “Si selezionato da @utente”).
- L’agent riceve la selezione come messaggio in ingresso e risponde.
Note:
- I callback dei pulsanti usano verifica HMAC-SHA256 (automatica, nessuna configurazione necessaria).
- Mattermost rimuove i callback data dalle risposte API (feature di sicurezza), quindi tutti i pulsanti vengono rimossi al click — la rimozione parziale non e possibile.
- Gli action ID contenenti trattini o underscore sono sanitizzati automaticamente (limitazione del routing Mattermost).
Configurazione:
channels.mattermost.capabilities: array di stringhe capability. Aggiungi"inlineButtons"per abilitare la descrizione dello strumento pulsanti nel system prompt dell’agent.channels.mattermost.interactions.callbackBaseUrl: URL base esterno opzionale per i callback dei pulsanti (ad esempiohttps://gateway.example.com). Usalo quando Mattermost non puo raggiungere il gateway al suo host di bind direttamente.- Nelle configurazioni multi-account, puoi impostare lo stesso campo sotto
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl. - Se
interactions.callbackBaseUrle omesso, OpenClaw deriva l’URL callback dagateway.customBindHost+gateway.port, poi fa fallback ahttp://localhost:<port>. - Regola di raggiungibilita: l’URL callback dei pulsanti deve essere raggiungibile dal server Mattermost.
localhostfunziona solo quando Mattermost e OpenClaw girano sullo stesso host/namespace di rete. - Se il tuo target callback e privato/tailnet/interno, aggiungi il suo host/dominio a
ServiceSettings.AllowedUntrustedInternalConnectionsdi Mattermost.
Integrazione API diretta (script esterni)
Script esterni e webhook possono pubblicare pulsanti direttamente via l’API REST Mattermost
invece di passare attraverso lo strumento message dell’agent. Usa buildButtonAttachments() dall’
estensione quando possibile; se pubblichi JSON grezzo, segui queste regole:
Struttura payload:
{
channel_id: "<channelId>",
message: "Scegli un'opzione:",
props: {
attachments: [
{
actions: [
{
id: "mybutton01", // solo alfanumerici -- vedi sotto
type: "button", // obbligatorio, o i click vengono ignorati silenziosamente
name: "Approva", // etichetta visualizzata
style: "primary", // opzionale: "default", "primary", "danger"
integration: {
url: "https://gateway.example.com/mattermost/interactions/default",
context: {
action_id: "mybutton01", // deve corrispondere all'id del pulsante (per il lookup del nome)
action: "approve",
// ... campi personalizzati ...
_token: "<hmac>", // vedi sezione HMAC sotto
},
},
},
],
},
],
},
}
Regole critiche:
- Gli attachment vanno in
props.attachments, non inattachmentsdi livello superiore (ignorati silenziosamente). - Ogni azione necessita di
type: "button"— senza, i click vengono assorbiti silenziosamente. - Ogni azione necessita di un campo
id— Mattermost ignora le azioni senza ID. - L’
iddell’azione deve essere solo alfanumerico ([a-zA-Z0-9]). Trattini e underscore rompono il routing lato server di Mattermost (restituisce 404). Rimuovili prima dell’uso. context.action_iddeve corrispondere all’iddel pulsante cosi il messaggio di conferma mostra il nome del pulsante (es. “Approva”) invece di un ID grezzo.context.action_ide obbligatorio — l’handler di interazione restituisce 400 senza di esso.
Generazione token HMAC:
Il gateway verifica i click sui pulsanti con HMAC-SHA256. Gli script esterni devono generare token che corrispondono alla logica di verifica del gateway:
- Deriva il segreto dal bot token:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - Costruisci l’oggetto context con tutti i campi eccetto
_token. - Serializza con chiavi ordinate e senza spazi (il gateway usa
JSON.stringifycon chiavi ordinate, che produce output compatto). - Firma:
HMAC-SHA256(key=secret, data=serializedContext) - Aggiungi il digest hex risultante come
_tokennel context.
Esempio 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}
Insidie HMAC comuni:
json.dumpsdi Python aggiunge spazi per impostazione predefinita ({"key": "val"}). Usaseparators=(",", ":")per corrispondere all’output compatto di JavaScript ({"key":"val"}).- Firma sempre tutti i campi del context (meno
_token). Il gateway rimuove_tokenpoi firma tutto il resto. Firmare un sottoinsieme causa fallimento silenzioso della verifica. - Usa
sort_keys=True— il gateway ordina le chiavi prima di firmare, e Mattermost potrebbe riordinare i campi del context quando salva il payload. - Deriva il segreto dal bot token (deterministico), non da byte casuali. Il segreto deve essere lo stesso tra il processo che crea i pulsanti e il gateway che verifica.
Adapter directory
Il plugin Mattermost include un adapter directory che risolve nomi di canale e utente
via l’API Mattermost. Questo abilita i target #channel-name e @username in
openclaw message send e nelle consegne cron/webhook.
Non serve configurazione — l’adapter usa il bot token dal config dell’account.
Multi-account
Mattermost supporta piu account sotto channels.mattermost.accounts:
{
channels: {
mattermost: {
accounts: {
default: { name: "Primario", botToken: "mm-token", baseUrl: "https://chat.example.com" },
alerts: { name: "Avvisi", botToken: "mm-token-2", baseUrl: "https://alerts.example.com" },
},
},
},
}
Risoluzione problemi
- Nessuna risposta nei canali: assicurati che il bot sia nel canale e menzionalo (oncall), usa un prefisso trigger (onchar), o imposta
chatmode: "onmessage". - Errori di autenticazione: controlla il bot token, l’URL base e se l’account e abilitato.
- Problemi multi-account: le variabili env si applicano solo all’account
default. - I pulsanti appaiono come riquadri bianchi: l’agent potrebbe inviare dati dei pulsanti malformati. Controlla che ogni pulsante abbia sia il campo
textchecallback_data. - I pulsanti si renderizzano ma i click non fanno nulla: verifica che
AllowedUntrustedInternalConnectionsnel config del server Mattermost includa127.0.0.1 localhost, e cheEnablePostActionIntegrationsiatruenei ServiceSettings. - I pulsanti restituiscono 404 al click: l’
iddel pulsante probabilmente contiene trattini o underscore. Il router delle azioni di Mattermost si rompe con ID non alfanumerici. Usa solo[a-zA-Z0-9]. - Il gateway registra
invalid _token: mismatch HMAC. Controlla di firmare tutti i campi del context (non un sottoinsieme), di usare chiavi ordinate e JSON compatto (senza spazi). Vedi la sezione HMAC sopra. - Il gateway registra
missing _token in context: il campo_tokennon e nel context del pulsante. Assicurati che sia incluso quando costruisci il payload di integrazione. - Il messaggio di conferma mostra un ID grezzo invece del nome del pulsante:
context.action_idnon corrisponde all’iddel pulsante. Imposta entrambi allo stesso valore sanitizzato. - L’agent non sa dei pulsanti: aggiungi
capabilities: ["inlineButtons"]al config del canale Mattermost.