Mattermost(外掛)

狀態:透過外掛支援(bot token + WebSocket 事件)。支援頻道、群組和 DM。 Mattermost 是一個可自行託管的團隊通訊平台;請參閱官方網站 mattermost.com 了解產品詳情和下載。

需要外掛

Mattermost 以外掛形式提供,不包含在核心安裝中。

透過 CLI 安裝(npm 登錄):

openclaw plugins install @openclaw/mattermost

本地 checkout(從 git 儲存庫執行時):

openclaw plugins install ./extensions/mattermost

如果你在設定/引導過程中選擇 Mattermost 且偵測到 git checkout,OpenClaw 會自動提供本地安裝路徑。

詳情:外掛

快速設定

  1. 安裝 Mattermost 外掛。
  2. 建立 Mattermost 機器人帳戶並複製 bot token
  3. 複製 Mattermost 基底 URL(例如 https://chat.example.com)。
  4. 設定 OpenClaw 並啟動閘道。

最小設定:

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

原生斜線指令

原生斜線指令需要選擇啟用。啟用後,OpenClaw 會透過 Mattermost API 註冊 oc_* 斜線指令,並在閘道 HTTP 伺服器上接收回呼 POST。

{
  channels: {
    mattermost: {
      commands: {
        native: true,
        nativeSkills: true,
        callbackPath: "/api/channels/mattermost/command",
        // Use when Mattermost cannot reach the gateway directly (reverse proxy/public URL).
        callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
      },
    },
  },
}

注意事項:

  • native: "auto" 在 Mattermost 中預設為停用。設定 native: true 以啟用。
  • 如果省略 callbackUrl,OpenClaw 會從閘道主機/連接埠 + callbackPath 推導。
  • 在多帳戶設定中,commands 可設定在最上層或 channels.mattermost.accounts.<id>.commands 下(帳戶值覆寫最上層欄位)。
  • 指令回呼透過每指令 token 驗證,token 檢查失敗時會安全失敗。
  • 可達性要求:回呼端點必須可從 Mattermost 伺服器存取。
    • 除非 Mattermost 與 OpenClaw 在同一主機/網路命名空間中,否則不要將 callbackUrl 設為 localhost
    • 除非該 URL 將 /api/channels/mattermost/command 反向代理到 OpenClaw,否則不要將 callbackUrl 設為你的 Mattermost 基底 URL。
    • 快速檢查:curl https://<gateway-host>/api/channels/mattermost/command;GET 請求應從 OpenClaw 回傳 405 Method Not Allowed,而非 404
  • Mattermost 出站允許名單要求:
    • 如果你的回呼目標為私有/tailnet/內部位址,請將 Mattermost ServiceSettings.AllowedUntrustedInternalConnections 設定為包含回呼主機/網域。
    • 使用主機/網域項目,而非完整 URL。
      • 正確:gateway.tailnet-name.ts.net
      • 錯誤:https://gateway.tailnet-name.ts.net

環境變數(預設帳戶)

如果你偏好環境變數,在閘道主機上設定:

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

環境變數僅適用於預設帳戶(default)。其他帳戶必須使用設定值。

聊天模式

Mattermost 會自動回應 DM。頻道行為由 chatmode 控制:

  • oncall(預設):僅在頻道中被 @提及時回應。
  • onmessage:回應每則頻道訊息。
  • onchar:當訊息以觸發前綴開頭時回應。

設定範例:

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

注意事項:

  • onchar 仍會回應明確的 @提及。
  • channels.mattermost.requireMention 在舊版設定中仍被接受,但建議使用 chatmode

討論串與工作階段

使用 channels.mattermost.replyToMode 控制頻道和群組回覆是留在主頻道還是在觸發貼文下開啟討論串。

  • off(預設):僅在收到的貼文已在討論串中時才在討論串中回覆。
  • first:對於最上層的頻道/群組貼文,在該貼文下開啟討論串,並將對話路由到討論串範圍的工作階段。
  • all:目前在 Mattermost 中與 first 行為相同。
  • 私訊忽略此設定,保持非討論串形式。

設定範例:

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

注意事項:

  • 討論串範圍的工作階段使用觸發貼文的 ID 作為討論串根。
  • firstall 目前等效,因為一旦 Mattermost 有了討論串根,後續的分段和媒體會繼續在同一討論串中。

存取控制(DM)

  • 預設:channels.mattermost.dmPolicy = "pairing"(未知發送者會收到配對碼)。
  • 核准方式:
    • openclaw pairing list mattermost
    • openclaw pairing approve mattermost <CODE>
  • 公開 DM:channels.mattermost.dmPolicy="open" 加上 channels.mattermost.allowFrom=["*"]

頻道(群組)

  • 預設:channels.mattermost.groupPolicy = "allowlist"(需要提及)。
  • 使用 channels.mattermost.groupAllowFrom 設定發送者允許名單(建議使用使用者 ID)。
  • @username 匹配是可變的,僅在 channels.mattermost.dangerouslyAllowNameMatching: true 時啟用。
  • 開放頻道:channels.mattermost.groupPolicy="open"(需要提及)。
  • 執行時注意:如果 channels.mattermost 完全不存在,執行時群組檢查會回退到 groupPolicy="allowlist"(即使已設定 channels.defaults.groupPolicy)。

傳出送達目標

搭配 openclaw message send 或 cron/webhook 使用這些目標格式:

  • channel:<id> 用於頻道
  • user:<id> 用於 DM
  • @username 用於 DM(透過 Mattermost API 解析)

單純的不透明 ID(如 64ifufp...)在 Mattermost 中具有歧義性(使用者 ID vs 頻道 ID)。

OpenClaw 以使用者優先方式解析:

  • 如果該 ID 以使用者身份存在(GET /api/v4/users/<id> 成功),OpenClaw 會透過 /api/v4/channels/direct 解析直接頻道來傳送 DM
  • 否則該 ID 被視為頻道 ID

如果你需要確定性行為,請始終使用明確前綴(user:<id> / channel:<id>)。

回應(訊息工具)

  • 使用 message action=react 搭配 channel=mattermost
  • messageId 是 Mattermost 的貼文 ID。
  • emoji 接受如 thumbsup:+1: 的名稱(冒號是選填的)。
  • 設定 remove=true(布林值)以移除回應。
  • 回應新增/移除事件會作為系統事件轉發到路由的代理工作階段。

範例:

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

設定:

  • channels.mattermost.actions.reactions:啟用/停用回應操作(預設 true)。
  • 每帳戶覆寫:channels.mattermost.accounts.<id>.actions.reactions

互動式按鈕(訊息工具)

傳送帶有可點擊按鈕的訊息。當使用者點擊按鈕時,代理會收到選擇並可以回應。

透過在頻道功能中新增 inlineButtons 來啟用按鈕:

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

使用 message action=send 搭配 buttons 參數。按鈕是 2D 陣列(按鈕的行列):

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

按鈕欄位:

  • text(必填):顯示標籤。
  • callback_data(必填):點擊時回傳的值(用作操作 ID)。
  • style(選填):"default""primary""danger"

當使用者點擊按鈕時:

  1. 所有按鈕會被替換為確認行(例如「✓ Yes selected by @user」)。
  2. 代理收到選擇作為收到的訊息並回應。

注意事項:

  • 按鈕回呼使用 HMAC-SHA256 驗證(自動化,無需設定)。
  • Mattermost 會從 API 回應中移除回呼資料(安全功能),因此所有按鈕在點擊時會被移除——無法部分移除。
  • 包含連字號或底線的操作 ID 會自動清理(Mattermost 路由限制)。

設定:

  • channels.mattermost.capabilities:功能字串陣列。新增 "inlineButtons" 以在代理系統提示中啟用按鈕工具描述。
  • channels.mattermost.interactions.callbackBaseUrl:選填的外部基底 URL 用於按鈕回呼(例如 https://gateway.example.com)。當 Mattermost 無法直接存取閘道的綁定主機時使用。
  • 在多帳戶設定中,也可在 channels.mattermost.accounts.<id>.interactions.callbackBaseUrl 下設定。
  • 如果省略 interactions.callbackBaseUrl,OpenClaw 會從 gateway.customBindHost + gateway.port 推導回呼 URL,然後回退到 http://localhost:<port>
  • 可達性規則:按鈕回呼 URL 必須可從 Mattermost 伺服器存取。localhost 僅在 Mattermost 和 OpenClaw 在同一主機/網路命名空間中時有效。
  • 如果你的回呼目標為私有/tailnet/內部,請將其主機/網域加入 Mattermost ServiceSettings.AllowedUntrustedInternalConnections

直接 API 整合(外部腳本)

外部腳本和 webhook 可以直接透過 Mattermost REST API 發布按鈕,而不需透過代理的 message 工具。盡可能使用擴充套件中的 buildButtonAttachments();如果發布原始 JSON,請遵循以下規則:

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
              },
            },
          },
        ],
      },
    ],
  },
}

關鍵規則:

  1. 附件放在 props.attachments 中,而非最上層的 attachments(會被靜默忽略)。
  2. 每個操作需要 type: "button" — 缺少它,點擊會被靜默吞掉。
  3. 每個操作需要 id 欄位 — Mattermost 會忽略沒有 ID 的操作。
  4. 操作 id 必須是純英數字[a-zA-Z0-9])。連字號和底線會導致 Mattermost 的伺服器端操作路由中斷(回傳 404)。使用前請去除它們。
  5. context.action_id 必須與按鈕的 id 相符,這樣確認訊息才會顯示按鈕名稱(例如「Approve」)而非原始 ID。
  6. context.action_id 是必填的 — 互動處理程式在缺少時回傳 400。

HMAC token 產生:

閘道透過 HMAC-SHA256 驗證按鈕點擊。外部腳本必須產生與閘道驗證邏輯相符的 token:

  1. 從 bot token 推導密鑰: HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. 建立包含所有欄位(除了 _token)的 context 物件。
  3. 排序的鍵無空格序列化(閘道使用排序鍵的 JSON.stringify,產生緊湊輸出)。
  4. 簽署:HMAC-SHA256(key=secret, data=serializedContext)
  5. 將產生的十六進位摘要作為 _token 加入 context。

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}

常見 HMAC 陷阱:

  • Python 的 json.dumps 預設會加入空格({"key": "val"})。使用 separators=(",", ":") 以配合 JavaScript 的緊湊輸出({"key":"val"})。
  • 務必簽署所有 context 欄位(減去 _token)。閘道會移除 _token 然後簽署其餘所有項目。簽署子集合會導致靜默驗證失敗。
  • 使用 sort_keys=True — 閘道在簽署前會排序鍵,Mattermost 在儲存 payload 時可能會重新排列 context 欄位。
  • 從 bot token 推導密鑰(確定性),而非隨機位元組。密鑰在建立按鈕的處理程序和驗證的閘道之間必須相同。

目錄配接器

Mattermost 外掛包含一個目錄配接器,透過 Mattermost API 解析頻道和使用者名稱。這讓 openclaw message send 和 cron/webhook 送達中的 #channel-name@username 目標得以運作。

無需設定 — 配接器使用帳戶設定中的 bot token。

多帳戶

Mattermost 支援在 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" },
      },
    },
  },
}

疑難排解

  • 頻道中沒有回覆:確認機器人在頻道中並提及它(oncall),使用觸發前綴(onchar),或設定 chatmode: "onmessage"
  • 驗證錯誤:檢查 bot token、基底 URL 以及帳戶是否已啟用。
  • 多帳戶問題:環境變數僅適用於 default 帳戶。
  • 按鈕顯示為白色方塊:代理可能傳送了格式錯誤的按鈕資料。檢查每個按鈕是否同時有 textcallback_data 欄位。
  • 按鈕顯示但點擊無反應:確認 Mattermost 伺服器設定中的 AllowedUntrustedInternalConnections 包含 127.0.0.1 localhost,且 ServiceSettings 中 EnablePostActionIntegrationtrue
  • 按鈕點擊回傳 404:按鈕 id 可能包含連字號或底線。Mattermost 的操作路由器在非英數字 ID 上會中斷。僅使用 [a-zA-Z0-9]
  • 閘道記錄 invalid _token:HMAC 不匹配。檢查你是否簽署了所有 context 欄位(而非子集),使用排序鍵,以及使用緊湊 JSON(無空格)。參閱上方 HMAC 章節。
  • 閘道記錄 missing _token in context:按鈕的 context 中缺少 _token 欄位。確保在建立整合 payload 時包含它。
  • 確認顯示原始 ID 而非按鈕名稱:context.action_id 與按鈕的 id 不符。將兩者設為相同的清理值。
  • 代理不知道按鈕功能:在 Mattermost 頻道設定中新增 capabilities: ["inlineButtons"]