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

  1. Installa il plugin Mattermost.
  2. Crea un account bot Mattermost e copia il bot token.
  3. Copia l’URL base di Mattermost (es. https://chat.example.com).
  4. 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. Imposta native: true per abilitare.
  • Se callbackUrl e omesso, OpenClaw ne deriva uno da host/porta del gateway + callbackPath.
  • Per configurazioni multi-account, commands puo essere impostato a livello superiore o sotto channels.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 callbackUrl a localhost a meno che Mattermost non giri sullo stesso host/namespace di rete di OpenClaw.
    • Non impostare callbackUrl al tuo URL base Mattermost a meno che quell’URL non faccia reverse proxy di /api/channels/mattermost/command verso OpenClaw.
    • Un controllo rapido e curl https://<gateway-host>/api/channels/mattermost/command; un GET dovrebbe restituire 405 Method Not Allowed da OpenClaw, non 404.
  • Requisito allowlist egress Mattermost:
    • Se il tuo callback punta a indirizzi privati/tailnet/interni, imposta ServiceSettings.AllowedUntrustedInternalConnections di 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

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:

  • onchar risponde comunque alle @menzioni esplicite.
  • channels.mattermost.requireMention e rispettato per config legacy ma chatmode e 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 di first per 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.
  • first e all sono 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 mattermost
    • openclaw pairing approve mattermost <CODE>
  • DM pubblici: channels.mattermost.dmPolicy="open" piu channels.mattermost.allowFrom=["*"].

Canali (gruppi)

  • Predefinito: channels.mattermost.groupPolicy = "allowlist" (gating menzione).
  • Allowlist mittenti con channels.mattermost.groupAllowFrom (user ID consigliati).
  • Il matching @username e mutabile e abilitato solo quando channels.mattermost.dangerouslyAllowNameMatching: true.
  • Canali aperti: channels.mattermost.groupPolicy="open" (gating menzione).
  • Nota runtime: se channels.mattermost e completamente assente, il runtime torna a groupPolicy="allowlist" per i controlli di gruppo (anche se channels.defaults.groupPolicy e impostato).

Target per consegna in uscita

Usa questi formati target con openclaw message send o cron/webhook:

  • channel:<id> per un canale
  • user:<id> per un DM
  • @username per 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=react con channel=mattermost.
  • messageId e l’id del post Mattermost.
  • emoji accetta nomi come thumbsup o :+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:

  1. Tutti i pulsanti sono sostituiti con una riga di conferma (es. “Si selezionato da @utente”).
  2. 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 esempio https://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.callbackBaseUrl e omesso, OpenClaw deriva l’URL callback da gateway.customBindHost + gateway.port, poi fa fallback a http://localhost:<port>.
  • Regola di raggiungibilita: l’URL callback dei pulsanti deve essere raggiungibile dal server Mattermost. localhost funziona 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.AllowedUntrustedInternalConnections di 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:

  1. Gli attachment vanno in props.attachments, non in attachments di livello superiore (ignorati silenziosamente).
  2. Ogni azione necessita di type: "button" — senza, i click vengono assorbiti silenziosamente.
  3. Ogni azione necessita di un campo id — Mattermost ignora le azioni senza ID.
  4. L’id dell’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.
  5. context.action_id deve corrispondere all’id del pulsante cosi il messaggio di conferma mostra il nome del pulsante (es. “Approva”) invece di un ID grezzo.
  6. context.action_id e 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:

  1. Deriva il segreto dal bot token: HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. Costruisci l’oggetto context con tutti i campi eccetto _token.
  3. Serializza con chiavi ordinate e senza spazi (il gateway usa JSON.stringify con chiavi ordinate, che produce output compatto).
  4. Firma: HMAC-SHA256(key=secret, data=serializedContext)
  5. Aggiungi il digest hex risultante come _token nel 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.dumps di Python aggiunge spazi per impostazione predefinita ({"key": "val"}). Usa separators=(",", ":") per corrispondere all’output compatto di JavaScript ({"key":"val"}).
  • Firma sempre tutti i campi del context (meno _token). Il gateway rimuove _token poi 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 text che callback_data.
  • I pulsanti si renderizzano ma i click non fanno nulla: verifica che AllowedUntrustedInternalConnections nel config del server Mattermost includa 127.0.0.1 localhost, e che EnablePostActionIntegration sia true nei ServiceSettings.
  • I pulsanti restituiscono 404 al click: l’id del 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 _token non 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_id non corrisponde all’id del pulsante. Imposta entrambi allo stesso valore sanitizzato.
  • L’agent non sa dei pulsanti: aggiungi capabilities: ["inlineButtons"] al config del canale Mattermost.