Mattermost (plugin)

Status: obslugiwany przez plugin (token bota + zdarzenia WebSocket). Kanaly, grupy i DM sa obslugiwane. Mattermost to samodzielnie hostowalnia platforma wiadomosci zespolowych; zobacz oficjalna strone na mattermost.com po szczegoly produktu i pliki do pobrania.

Wymagany plugin

Mattermost jest dostarczany jako plugin i nie jest dolaczony do instalacji podstawowej.

Instalacja przez CLI (rejestr npm):

openclaw plugins install @openclaw/mattermost

Lokalny checkout (przy uruchomieniu z repozytorium git):

openclaw plugins install ./extensions/mattermost

Jesli wybierzesz Mattermost podczas konfiguracji/onboardingu i zostanie wykryty checkout git, OpenClaw automatycznie zaproponuje sciezke instalacji lokalnej.

Szczegoly: Pluginy

Szybka konfiguracja

  1. Zainstaluj plugin Mattermost.
  2. Utworz konto bota Mattermost i skopiuj token bota.
  3. Skopiuj bazowy URL Mattermost (np. https://chat.example.com).
  4. Skonfiguruj OpenClaw i uruchom gateway.

Minimalna konfiguracja:

{
  channels: {
    mattermost: {
      enabled: true,
      botToken: "mm-token",
      baseUrl: "https://chat.example.com",
      dmPolicy: "pairing",
    },
  },
}

Natywne polecenia slash

Natywne polecenia slash sa wlaczane na zadanie. Po wlaczeniu OpenClaw rejestruje polecenia slash oc_* przez API Mattermost i odbiera callbackowe POST-y na serwerze HTTP gateway.

{
  channels: {
    mattermost: {
      commands: {
        native: true,
        nativeSkills: true,
        callbackPath: "/api/channels/mattermost/command",
        // Uzyj gdy Mattermost nie moze bezposrednio osiagnac gateway (reverse proxy/publiczny URL).
        callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
      },
    },
  },
}

Uwagi:

  • native: "auto" domyslnie jest wylaczone dla Mattermost. Ustaw native: true aby wlaczyc.
  • Jesli callbackUrl jest pominiety, OpenClaw wyprowadza go z hosta/portu gateway + callbackPath.
  • W konfiguracjach wielokontowych commands moze byc ustawione na najwyzszym poziomie lub pod channels.mattermost.accounts.<id>.commands (wartosci konta nadpisuja pola najwyzszego poziomu).
  • Callbacki polecen sa walidowane tokenami per polecenie i odrzucaja zamkniete gdy sprawdzenie tokenu nie powiedzie sie.
  • Wymog osiagalnosci: endpoint callbacku musi byc osiagalny z serwera Mattermost.
    • Nie ustawiaj callbackUrl na localhost, chyba ze Mattermost dziala na tym samym hoscie/przestrzeni sieciowej co OpenClaw.
    • Nie ustawiaj callbackUrl na bazowy URL Mattermost, chyba ze ten URL proxyuje /api/channels/mattermost/command do OpenClaw.
    • Szybkie sprawdzenie: curl https://<gateway-host>/api/channels/mattermost/command; GET powinien zwrocic 405 Method Not Allowed z OpenClaw, nie 404.
  • Wymog listy dozwolonych egress Mattermost:
    • Jesli twoj callback celuje w prywatne/tailnetowe/wewnetrzne adresy, ustaw Mattermost ServiceSettings.AllowedUntrustedInternalConnections aby zawieral host/domene callbacku.
    • Uzywaj wpisow host/domena, nie pelnych URL-i.
      • Dobrze: gateway.tailnet-name.ts.net
      • Zle: https://gateway.tailnet-name.ts.net

Zmienne srodowiskowe (domyslne konto)

Ustaw je na hoscie gateway jesli wolisz zmienne srodowiskowe:

  • MATTERMOST_BOT_TOKEN=...
  • MATTERMOST_URL=https://chat.example.com

Zmienne srodowiskowe dotycza tylko domyslnego konta (default). Inne konta musza uzywac wartosci konfiguracji.

Tryby czatu

Mattermost odpowiada na DM automatycznie. Zachowanie kanalow jest kontrolowane przez chatmode:

  • oncall (domyslnie): odpowiadaj tylko gdy @wspomniano na kanalach.
  • onmessage: odpowiadaj na kazda wiadomosc kanalu.
  • onchar: odpowiadaj gdy wiadomosc zaczyna sie od prefiksu wyzwalajacego.

Przyklad konfiguracji:

{
  channels: {
    mattermost: {
      chatmode: "onchar",
      oncharPrefixes: [">", "!"],
    },
  },
}

Uwagi:

  • onchar nadal odpowiada na jawne @wzmianki.
  • channels.mattermost.requireMention jest honorowane dla starszych konfiguracji, ale preferowany jest chatmode.

Watkowanie i sesje

Uzyj channels.mattermost.replyToMode aby kontrolowac, czy odpowiedzi na kanalach i grupach pozostaja na glownym kanale czy zaczynaja watek pod postem wyzwalajacym.

  • off (domyslnie): odpowiadaj w watku tylko gdy post przychodzacy juz jest w watku.
  • first: dla postow kanalowych/grupowych najwyzszego poziomu, zacznij watek pod tym postem i kieruj rozmowe do sesji o zakresie watku.
  • all: takie samo zachowanie jak first dla Mattermost dzisiaj.
  • Wiadomosci bezposrednie ignoruja to ustawienie i pozostaja bez watkow.

Przyklad konfiguracji:

{
  channels: {
    mattermost: {
      replyToMode: "all",
    },
  },
}

Uwagi:

  • Sesje o zakresie watku uzywaja ID postu wyzwalajacego jako korzenia watku.
  • first i all sa obecnie rownowazne, poniewaz gdy Mattermost ma korzen watku, kolejne fragmenty i media kontynuuja w tym samym watku.

Kontrola dostepu (DM)

  • Domyslnie: channels.mattermost.dmPolicy = "pairing" (nieznani nadawcy otrzymuja kod parowania).
  • Zatwierdzanie przez:
    • openclaw pairing list mattermost
    • openclaw pairing approve mattermost <CODE>
  • Publiczne DM: channels.mattermost.dmPolicy="open" plus channels.mattermost.allowFrom=["*"].

Kanaly (grupy)

  • Domyslnie: channels.mattermost.groupPolicy = "allowlist" (bramkowane wzmiankami).
  • Dodaj nadawcow do listy dozwolonych przez channels.mattermost.groupAllowFrom (zalecane ID uzytkownikow).
  • Dopasowywanie @username jest zmienne i wlaczane tylko gdy channels.mattermost.dangerouslyAllowNameMatching: true.
  • Otwarte kanaly: channels.mattermost.groupPolicy="open" (bramkowane wzmiankami).
  • Uwaga runtime: jesli channels.mattermost calkowicie brakuje, runtime stosuje zastepczym groupPolicy="allowlist" dla sprawdzen grupowych (nawet jesli channels.defaults.groupPolicy jest ustawione).

Cele dostarczania wychodzacego

Uzyj tych formatow celow z openclaw message send lub cron/webhookami:

  • channel:<id> dla kanalu
  • user:<id> dla DM
  • @username dla DM (rozwiazywane przez API Mattermost)

Nagie nieprzejrzyste ID (jak 64ifufp...) sa niejednoznaczne w Mattermost (ID uzytkownika vs ID kanalu).

OpenClaw rozwiazuje je najpierw jako uzytkownika:

  • Jesli ID istnieje jako uzytkownik (GET /api/v4/users/<id> sie powiedzie), OpenClaw wysyla DM przez rozwiazanie bezposredniego kanalu przez /api/v4/channels/direct.
  • W przeciwnym razie ID jest traktowane jako ID kanalu.

Jesli potrzebujesz deterministycznego zachowania, zawsze uzywaj jawnych prefiksow (user:<id> / channel:<id>).

Reakcje (narzedzie wiadomosci)

  • Uzyj message action=react z channel=mattermost.
  • messageId to ID postu Mattermost.
  • emoji akceptuje nazwy jak thumbsup lub :+1: (dwukropki sa opcjonalne).
  • Ustaw remove=true (boolean) aby usunac reakcje.
  • Zdarzenia dodawania/usuwania reakcji sa przekazywane jako zdarzenia systemowe do sesji routowanego agenta.

Przyklady:

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

Konfiguracja:

  • channels.mattermost.actions.reactions: wlaczenie/wylaczenie akcji reakcji (domyslnie true).
  • Nadpisanie per konto: channels.mattermost.accounts.<id>.actions.reactions.

Interaktywne przyciski (narzedzie wiadomosci)

Wysylaj wiadomosci z klicalnymi przyciskami. Gdy uzytkownik kliknie przycisk, agent otrzymuje wybor i moze odpowiedziec.

Wlacz przyciski dodajac inlineButtons do mozliwosci kanalu:

{
  channels: {
    mattermost: {
      capabilities: ["inlineButtons"],
    },
  },
}

Uzyj message action=send z parametrem buttons. Przyciski to tablica 2D (wiersze przyciskow):

message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]

Pola przyciskow:

  • text (wymagane): etykieta wyswietlania.
  • callback_data (wymagane): wartosc wyslana po kliknieciu (uzywana jako ID akcji).
  • style (opcjonalne): "default", "primary" lub "danger".

Gdy uzytkownik kliknie przycisk:

  1. Wszystkie przyciski sa zastepowane linia potwierdzenia (np. “Wybrano Yes przez @user”).
  2. Agent otrzymuje wybor jako wiadomosc przychodzaca i odpowiada.

Uwagi:

  • Callbacki przyciskow uzywaja weryfikacji HMAC-SHA256 (automatycznie, bez konfiguracji).
  • Mattermost usuwa callback data ze swoich odpowiedzi API (funkcja bezpieczenstwa), wiec wszystkie przyciski sa usuwane po kliknieciu — czesciowe usuwanie nie jest mozliwe.
  • ID akcji zawierajace myslniki lub podkreslenia sa automatycznie sanityzowane (ograniczenie routingu Mattermost).

Konfiguracja:

  • channels.mattermost.capabilities: tablica ciagu mozliwosci. Dodaj "inlineButtons" aby wlaczyc opis narzedzia przyciskow w promptcie systemowym agenta.
  • channels.mattermost.interactions.callbackBaseUrl: opcjonalny zewnetrzny bazowy URL dla callbackow przyciskow (np. https://gateway.example.com). Uzyj gdy Mattermost nie moze osiagnac gateway bezposrednio po hoscie powiazania.
  • W konfiguracjach wielokontowych mozesz rowniez ustawic to samo pole pod channels.mattermost.accounts.<id>.interactions.callbackBaseUrl.
  • Jesli interactions.callbackBaseUrl jest pominiety, OpenClaw wyprowadza URL callbacku z gateway.customBindHost + gateway.port, nastepnie stosuje zastepczym http://localhost:<port>.
  • Regula osiagalnosci: URL callbacku przyciskow musi byc osiagalny z serwera Mattermost. localhost dziala tylko gdy Mattermost i OpenClaw dzialaja na tym samym hoscie/przestrzeni sieciowej.
  • Jesli twoj cel callbacku jest prywatny/tailnetowy/wewnetrzny, dodaj jego host/domene do Mattermost ServiceSettings.AllowedUntrustedInternalConnections.

Bezposrednia integracja API (skrypty zewnetrzne)

Zewnetrzne skrypty i webhooki moga publikowac przyciski bezposrednio przez REST API Mattermost zamiast przechodzic przez narzedzie message agenta. Uzyj buildButtonAttachments() z rozszerzenia gdy to mozliwe; jesli publikujesz surowy JSON, przestrzegaj tych zasad:

Struktura payloadu:

{
  channel_id: "<channelId>",
  message: "Choose an option:",
  props: {
    attachments: [
      {
        actions: [
          {
            id: "mybutton01", // tylko alfanumeryczne — zobacz nizej
            type: "button", // wymagane, inaczej klikniecia sa cicho ignorowane
            name: "Approve", // etykieta wyswietlania
            style: "primary", // opcjonalnie: "default", "primary", "danger"
            integration: {
              url: "https://gateway.example.com/mattermost/interactions/default",
              context: {
                action_id: "mybutton01", // musi pasowac do id przycisku (dla wyszukania nazwy)
                action: "approve",
                // ... dowolne niestandardowe pola ...
                _token: "<hmac>", // zobacz sekcje HMAC ponizej
              },
            },
          },
        ],
      },
    ],
  },
}

Krytyczne zasady:

  1. Zalaczniki ida w props.attachments, nie w attachments najwyzszego poziomu (cicho ignorowane).
  2. Kazda akcja potrzebuje type: "button" — bez tego klikniecia sa cicho polykane.
  3. Kazda akcja potrzebuje pola id — Mattermost ignoruje akcje bez ID.
  4. id akcji musi byc tylko alfanumeryczne ([a-zA-Z0-9]). Myslniki i podkreslenia lamia routing akcji po stronie serwera Mattermost (zwraca 404). Usun je przed uzyciem.
  5. context.action_id musi pasowac do id przycisku, aby wiadomosc potwierdzenia pokazywala nazwe przycisku (np. “Approve”) zamiast surowego ID.
  6. context.action_id jest wymagane — handler interakcji zwraca 400 bez niego.

Generowanie tokenu HMAC:

Gateway weryfikuje klikniecia przyciskow za pomoca HMAC-SHA256. Zewnetrzne skrypty musza generowac tokeny pasujace do logiki weryfikacji gateway:

  1. Wyprowadz sekret z tokenu bota: HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. Zbuduj obiekt context ze wszystkimi polami oprocz _token.
  3. Serializuj z posortowanymi kluczami i bez spacji (gateway uzywa JSON.stringify z posortowanymi kluczami, co produkuje kompaktowe wyjscie).
  4. Podpisz: HMAC-SHA256(key=secret, data=serializedContext)
  5. Dodaj wynikowy hex digest jako _token w kontekscie.

Przyklad 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}

Czeste pulapki HMAC:

  • json.dumps Pythona domyslnie dodaje spacje ({"key": "val"}). Uzyj separators=(",", ":") aby dopasowac kompaktowe wyjscie JavaScript ({"key":"val"}).
  • Zawsze podpisuj wszystkie pola kontekstu (minus _token). Gateway usuwa _token nastepnie podpisuje wszystko pozostale. Podpisywanie podzbiorow powoduje cicha awarie weryfikacji.
  • Uzyj sort_keys=True — gateway sortuje klucze przed podpisywaniem, a Mattermost moze zmienic kolejnosc pol kontekstu podczas przechowywania payloadu.
  • Wyprowadz sekret z tokenu bota (deterministycznie), nie z losowych bajtow. Sekret musi byc taki sam w procesie tworzacym przyciski i gateway weryfikujacym.

Adapter katalogu

Plugin Mattermost zawiera adapter katalogu, ktory rozwiazuje nazwy kanalow i uzytkownikow przez API Mattermost. Umozliwia to cele #channel-name i @username w openclaw message send i dostarczaniu cron/webhook.

Konfiguracja nie jest potrzebna — adapter uzywa tokenu bota z konfiguracji konta.

Wiele kont

Mattermost obsluguje wiele kont pod 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" },
      },
    },
  },
}

Rozwiazywanie problemow

  • Brak odpowiedzi na kanalach: upewnij sie, ze bot jest na kanale i wspomnij go (oncall), uzyj prefiksu wyzwalajacego (onchar) lub ustaw chatmode: "onmessage".
  • Bledy autoryzacji: sprawdz token bota, bazowy URL i czy konto jest wlaczone.
  • Problemy z wieloma kontami: zmienne srodowiskowe dotycza tylko konta default.
  • Przyciski wyswietlaja sie jako biale pola: agent moze wysylac zle sformatowane dane przyciskow. Sprawdz, czy kazdy przycisk ma pola text i callback_data.
  • Przyciski sie renderuja, ale klikniecia nic nie robia: zweryfikuj AllowedUntrustedInternalConnections w konfiguracji serwera Mattermost zawiera 127.0.0.1 localhost i ze EnablePostActionIntegration jest true w ServiceSettings.
  • Przyciski zwracaja 404 po kliknieciu: id przycisku prawdopodobnie zawiera myslniki lub podkreslenia. Router akcji Mattermost lamie sie na niealfanumerycznych ID. Uzywaj tylko [a-zA-Z0-9].
  • Logi gateway invalid _token: niezgodnosc HMAC. Sprawdz, ze podpisujesz wszystkie pola kontekstu (nie podzbiory), uzywasz posortowanych kluczy i kompaktowego JSON (bez spacji). Zobacz sekcje HMAC powyzej.
  • Logi gateway missing _token in context: pole _token nie jest w kontekscie przycisku. Upewnij sie, ze jest dolaczone przy budowaniu payloadu integracji.
  • Potwierdzenie pokazuje surowe ID zamiast nazwy przycisku: context.action_id nie pasuje do id przycisku. Ustaw oba na ta sama sanityzowana wartosc.
  • Agent nie wie o przyciskach: dodaj capabilities: ["inlineButtons"] do konfiguracji kanalu Mattermost.