Mattermost(プラグイン)

ステータス:プラグインでサポート(Botトークン + WebSocketイベント)。チャンネル、グループ、DMに対応しています。 Mattermostはセルフホスト可能なチームメッセージングプラットフォームです。製品の詳細とダウンロードはmattermost.comをご覧ください。

プラグインが必要です

Mattermostはプラグインとして提供されており、コアインストールにはバンドルされていません。

CLI経由でインストール(npmレジストリ):

openclaw plugins install @openclaw/mattermost

ローカルチェックアウト(gitリポジトリから実行する場合):

openclaw plugins install ./extensions/mattermost

設定/オンボーディング時にMattermostを選択し、gitチェックアウトが検出された場合、OpenClawはローカルインストールパスを自動的に提案します。

詳細:プラグイン

クイックセットアップ

  1. Mattermostプラグインをインストールします。
  2. MattermostのBotアカウントを作成し、Botトークンをコピーします。
  3. MattermostのベースURLをコピーします(例:https://chat.example.com)。
  4. OpenClawを設定してGatewayを起動します。

最小設定:

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

ネイティブスラッシュコマンド

ネイティブスラッシュコマンドはオプトインです。有効にすると、OpenClawはMattermost APIを通じてoc_*スラッシュコマンドを登録し、Gateway HTTPサーバーでコールバックPOSTを受信します。

{
  channels: {
    mattermost: {
      commands: {
        native: true,
        nativeSkills: true,
        callbackPath: "/api/channels/mattermost/command",
        // MattermostがGatewayに直接到達できない場合に使用(リバースプロキシ/パブリックURL)。
        callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
      },
    },
  },
}

注意事項:

  • native: "auto"はMattermostではデフォルトで無効です。native: trueで有効にしてください。
  • callbackUrlを省略すると、OpenClawはGatewayのホスト/ポート + callbackPathから導出します。
  • マルチアカウント設定では、commandsをトップレベルまたはchannels.mattermost.accounts.<id>.commandsに設定できます(アカウント値がトップレベルフィールドをオーバーライド)。
  • コマンドコールバックはコマンドごとのトークンで検証され、トークンチェックが失敗した場合はクローズされます。
  • 到達性要件:コールバックエンドポイントはMattermostサーバーから到達可能でなければなりません。
    • MattermostがOpenClawと同じホスト/ネットワーク名前空間で実行されていない限り、callbackUrllocalhostに設定しないでください。
    • そのURLがOpenClawに/api/channels/mattermost/commandをリバースプロキシしていない限り、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

環境変数(デフォルトアカウント)

環境変数を使用する場合は、Gatewayホストで以下を設定してください:

  • 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と同じ動作。
  • DMはこの設定を無視し、非スレッドのまま。

設定例:

{
  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/webhooksで以下のターゲットフォーマットを使用します:

  • 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ツール)

  • message action=reactchannel=mattermostで使用します。
  • messageIdはMattermostの投稿IDです。
  • emojithumbsup:+1:のような名前を受け付けます(コロンは任意)。
  • remove=true(boolean)でリアクションを削除します。
  • リアクションの追加/削除イベントはシステムイベントとしてルーティングされたAgentセッションに転送されます。

使用例:

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

インタラクティブボタン(messageツール)

クリック可能なボタン付きメッセージを送信します。ユーザーがボタンをクリックすると、Agentが選択を受信して応答します。

ボタンを有効にするには、チャンネルケーパビリティにinlineButtonsを追加してください:

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

message action=sendbuttonsパラメータを使用します。ボタンは2次元配列(ボタンの行)です:

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. Agentが選択を受信メッセージとして受け取り応答します。

注意事項:

  • ボタンコールバックはHMAC-SHA256検証を使用します(自動、設定不要)。
  • Mattermostはcallbackデータをストリップするため(セキュリティ機能)、クリック時にすべてのボタンが削除されます。部分的な削除はできません。
  • ハイフンやアンダースコアを含むアクションIDは自動的にサニタイズされます(Mattermostルーティング制限)。

設定:

  • channels.mattermost.capabilities:ケーパビリティ文字列の配列。"inlineButtons"を追加するとAgentシステムプロンプトにボタンツールの説明が含まれます。
  • channels.mattermost.interactions.callbackBaseUrl:ボタンコールバック用の外部ベースURL(任意)(例:https://gateway.example.com)。MattermostがGatewayのバインドホストに直接到達できない場合に使用します。
  • マルチアカウント設定では、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は、Agentのmessageツールを経由せずMattermost REST APIを通じて直接ボタンを送信できます。可能であればエクステンションのbuildButtonAttachments()を使用してください。生のJSONを送信する場合は以下のルールに従ってください:

ペイロード構造:

{
  channel_id: "<channelId>",
  message: "Choose an option:",
  props: {
    attachments: [
      {
        actions: [
          {
            id: "mybutton01", // 英数字のみ(下記参照)
            type: "button", // 必須。ないとクリックが無視される
            name: "Approve", // 表示ラベル
            style: "primary", // 任意:"default"、"primary"、"danger"
            integration: {
              url: "https://gateway.example.com/mattermost/interactions/default",
              context: {
                action_id: "mybutton01", // ボタンidと一致する必要あり
                action: "approve",
                // ... カスタムフィールド ...
                _token: "<hmac>", // 下記HMACセクション参照
              },
            },
          },
        ],
      },
    ],
  },
}

重要なルール:

  1. attachmentsはprops.attachmentsに配置してください。トップレベルのattachmentsは無視されます。
  2. すべてのアクションにtype: "button"が必要です。ないとクリックが無視されます。
  3. すべてのアクションにidフィールドが必要です。Mattermostはidのないアクションを無視します。
  4. アクションid英数字のみ[a-zA-Z0-9])でなければなりません。ハイフンやアンダースコアはMattermostのサーバー側アクションルーティングを壊します(404が返る)。
  5. context.action_idはボタンのidと一致する必要があります。
  6. context.action_idは必須です。インタラクションハンドラーはなしの場合400を返します。

HMACトークン生成:

GatewayはHMAC-SHA256でボタンクリックを検証します。外部スクリプトはGatewayの検証ロジックに一致するトークンを生成する必要があります:

  1. Botトークンからシークレットを導出:HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. _token除くすべてのフィールドでコンテキストオブジェクトを構築
  3. ソートされたキースペースなしでシリアライズ(GatewayはソートされたキーのJSON.stringifyを使用、コンパクト出力)
  4. 署名:HMAC-SHA256(key=secret, data=serializedContext)
  5. 結果のhexダイジェストを_tokenとしてコンテキストに追加

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"})。JavaScriptのコンパクト出力({"key":"val"})に合わせるためseparators=(",", ":")を使用してください。
  • 常に_token以外のすべてのコンテキストフィールドを署名してください。Gatewayは_tokenを除去してから残りすべてを署名します。
  • sort_keys=Trueを使用してください。Gatewayは署名前にキーをソートし、Mattermostはペイロード保存時にcontextフィールドを並べ替える場合があります。
  • シークレットはBotトークンから導出してください(決定的)。ランダムバイトではありません。

ディレクトリアダプター

MattermostプラグインにはMattermost APIを通じてチャンネル名とユーザー名を解決するディレクトリアダプターが含まれています。これによりopenclaw message sendやcron/webhook配信で#channel-name@usernameターゲットが使用可能になります。

設定は不要です。アダプターはアカウント設定のBotトークンを使用します。

マルチアカウント

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

トラブルシューティング

  • チャンネルで返信がない場合:Botがチャンネルに参加しておりメンションしているか確認してください(oncall)。トリガープレフィックスを使用するか(onchar)、chatmode: "onmessage"を設定してください。
  • 認証エラー:Botトークン、ベースURL、アカウントの有効状態を確認してください。
  • マルチアカウントの問題:環境変数はdefaultアカウントにのみ適用されます。
  • ボタンが白い枠として表示される場合:Agentが不正なボタンデータを送信している可能性があります。各ボタンにtextcallback_dataの両フィールドがあるか確認してください。
  • ボタンは表示されるがクリックしても何も起きない場合:Mattermostサーバー設定でAllowedUntrustedInternalConnections127.0.0.1 localhostが含まれているか、ServiceSettingsでEnablePostActionIntegrationtrueになっているか確認してください。
  • クリック時にボタンが404を返す場合:ボタンのidにハイフンやアンダースコアが含まれている可能性があります。[a-zA-Z0-9]のみを使用してください。
  • Gatewayログにinvalid _tokenが表示される場合:HMACの不一致です。すべてのコンテキストフィールドを署名しているか、ソートされたキーを使用しているか、コンパクトJSON(スペースなし)を使用しているか確認してください。
  • Gatewayログにmissing _token in contextが表示される場合:ボタンのcontextに_tokenフィールドがありません。integrationペイロード構築時に含めてください。
  • 確認メッセージにボタン名ではなく生のIDが表示される場合:context.action_idがボタンのidと一致していません。両方を同じサニタイズ済み値に設定してください。
  • Agentがボタンについて認識していない場合:Mattermostチャンネル設定にcapabilities: ["inlineButtons"]を追加してください。