Developer and self-hosted

Mattermost

상태: 다운로드 가능한 Plugin(봇 토큰 + WebSocket 이벤트). Channels, 그룹, DM이 지원됩니다. Mattermost는 자체 호스팅 가능한 팀 메시징 플랫폼입니다. 제품 세부 정보와 다운로드는 공식 사이트 mattermost.com을 참조하세요.

설치

채널을 구성하기 전에 Mattermost를 설치하세요.

npm registry

openclaw plugins install @openclaw/mattermost

Local checkout

openclaw plugins install ./path/to/local/mattermost-plugin

세부 정보: Plugins

빠른 설정

  • Ensure plugin is available

    현재 패키징된 OpenClaw 릴리스에는 이미 포함되어 있습니다. 이전 버전 또는 사용자 지정 설치에서는 위 명령으로 수동 추가할 수 있습니다.

  • Create a Mattermost bot

    Mattermost 봇 계정을 만들고 봇 토큰을 복사합니다.

  • Copy the base URL

    Mattermost 기본 URL(예: https://chat.example.com)을 복사합니다.

  • Configure OpenClaw and start the 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",
          },
        },
      },
    }
    
    Behavior notes
    • native: "auto"는 Mattermost에서 기본적으로 비활성화됩니다. 활성화하려면 native: true를 설정하세요.
    • callbackUrl이 생략되면 OpenClaw가 Gateway 호스트/포트 + callbackPath에서 값을 파생합니다.
    • 다중 계정 설정의 경우 commands를 최상위 수준 또는 channels.mattermost.accounts.<id>.commands 아래에 설정할 수 있습니다(계정 값이 최상위 필드를 재정의함).
    • 명령 콜백은 OpenClaw가 oc_* 명령을 등록할 때 Mattermost가 반환한 명령별 토큰으로 검증됩니다.
    • OpenClaw는 각 콜백을 수락하기 전에 현재 Mattermost 명령 등록을 새로 고치므로, 삭제되었거나 다시 생성된 슬래시 명령의 오래된 토큰은 Gateway를 재시작하지 않아도 더 이상 수락되지 않습니다.
    • Mattermost API가 명령이 아직 최신인지 확인할 수 없으면 콜백 검증은 닫힌 상태로 실패합니다. 실패한 검증은 짧게 캐시되고, 동시 조회는 병합되며, 새로운 조회 시작은 재생 압력을 제한하기 위해 명령별로 속도 제한됩니다.
    • 등록 실패, 부분적인 시작, 또는 콜백 토큰이 확인된 명령의 등록 토큰과 일치하지 않는 경우 슬래시 콜백은 닫힌 상태로 실패합니다(한 명령에 유효한 토큰으로는 다른 명령의 업스트림 검증에 도달할 수 없음).
    Reachability requirement

    콜백 엔드포인트는 Mattermost 서버에서 도달 가능해야 합니다.

    • Mattermost가 OpenClaw와 동일한 호스트/네트워크 네임스페이스에서 실행되지 않는 한 callbackUrllocalhost로 설정하지 마세요.
    • 해당 URL이 /api/channels/mattermost/command를 OpenClaw로 리버스 프록시하지 않는 한 callbackUrl을 Mattermost 기본 URL로 설정하지 마세요.
    • 빠른 확인 방법은 curl https://<gateway-host>/api/channels/mattermost/command입니다. GET은 404가 아니라 OpenClaw의 405 Method Not Allowed를 반환해야 합니다.
    Mattermost egress allowlist

    콜백 대상이 비공개/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

    채팅 모드

    Mattermost는 DM에 자동으로 응답합니다. 채널 동작은 chatmode로 제어됩니다.

    oncall (default)

    채널에서 @멘션된 경우에만 응답합니다.

    onmessage

    모든 채널 메시지에 응답합니다.

    onchar

    메시지가 트리거 접두사로 시작할 때 응답합니다.

    구성 예시:

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

    참고:

    • onchar는 명시적 @멘션에도 계속 응답합니다.
    • channels.mattermost.requireMention은 레거시 구성에서 존중되지만 chatmode가 권장됩니다.

    스레드와 세션

    channels.mattermost.replyToMode를 사용하여 채널 및 그룹 응답이 기본 채널에 유지될지, 트리거한 게시물 아래의 스레드를 시작할지 제어합니다.

    • off(기본값): 인바운드 게시물이 이미 스레드 안에 있는 경우에만 스레드에 답글을 답니다.
    • first: 최상위 채널/그룹 게시물의 경우 해당 게시물 아래에 스레드를 시작하고 대화를 스레드 범위 세션으로 라우팅합니다.
    • all: 현재 Mattermost에서는 first와 동일한 동작입니다.
    • Direct messages는 이 설정을 무시하고 스레드 없이 유지됩니다.

    구성 예시:

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

    참고:

    • 스레드 범위 세션은 트리거한 게시물 ID를 스레드 루트로 사용합니다.
    • Mattermost에 스레드 루트가 생기면 후속 청크와 미디어가 같은 스레드에서 계속되므로 현재 firstall은 동일합니다.

    액세스 제어(DM)

    • 기본값: channels.mattermost.dmPolicy = "pairing"(알 수 없는 발신자는 페어링 코드를 받음).
    • 다음으로 승인:
      • openclaw pairing list mattermost
      • openclaw pairing approve mattermost &lt;CODE&gt;
    • 공개 DM: channels.mattermost.dmPolicy="open"channels.mattermost.allowFrom=["*"].

    채널(그룹)

    • 기본값: channels.mattermost.groupPolicy = "allowlist"(멘션 게이트 적용).
    • channels.mattermost.groupAllowFrom으로 발신자를 허용 목록에 추가합니다(사용자 ID 권장).
    • 채널별 멘션 재정의는 channels.mattermost.groups.<channelId>.requireMention 아래에 두거나, 기본값의 경우 channels.mattermost.groups["*"].requireMention 아래에 둡니다.
    • @username 일치는 변경 가능하며 channels.mattermost.dangerouslyAllowNameMatching: true일 때만 활성화됩니다.
    • 열린 채널: channels.mattermost.groupPolicy="open"(멘션 게이트 적용).
    • 런타임 참고: channels.mattermost가 완전히 누락된 경우 런타임은 그룹 검사에 대해 groupPolicy="allowlist"로 대체합니다(channels.defaults.groupPolicy가 설정되어 있어도).

    예시:

    {
      channels: {
        mattermost: {
          groupPolicy: "open",
          groups: {
            "*": { requireMention: true },
            "team-channel-id": { requireMention: false },
          },
        },
      },
    }
    

    아웃바운드 전달 대상

    openclaw message send 또는 cron/webhook에서 다음 대상 형식을 사용하세요.

    • channel:<id>: 채널
    • user:<id>: DM
    • @username: DM(Mattermost API를 통해 확인됨)

    DM 채널 재시도

    OpenClaw가 Mattermost DM 대상에 전송하면서 먼저 다이렉트 채널을 확인해야 하는 경우, 기본적으로 일시적인 다이렉트 채널 생성 실패를 재시도합니다.

    Mattermost Plugin 전체에 대해 이 동작을 조정하려면 channels.mattermost.dmChannelRetry를 사용하고, 한 계정에 대해서는 channels.mattermost.accounts.<id>.dmChannelRetry를 사용하세요.

    {
      channels: {
        mattermost: {
          dmChannelRetry: {
            maxRetries: 3,
            initialDelayMs: 1000,
            maxDelayMs: 10000,
            timeoutMs: 30000,
          },
        },
      },
    }
    

    참고:

    • 이는 모든 Mattermost API 호출이 아니라 DM 채널 생성(/api/v4/channels/direct)에만 적용됩니다.
    • 재시도는 속도 제한, 5xx 응답, 네트워크 또는 시간 초과 오류와 같은 일시적 실패에 적용됩니다.
    • 429 이외의 4xx 클라이언트 오류는 영구 오류로 처리되어 재시도되지 않습니다.

    미리보기 스트리밍

    Mattermost는 사고 과정, 도구 활동, 부분 답글 텍스트를 단일 초안 미리보기 게시물로 스트리밍하며, 최종 답변을 안전하게 보낼 수 있을 때 제자리에서 최종화합니다. 미리보기는 채널에 청크별 메시지를 반복해서 보내는 대신 같은 게시물 ID에서 업데이트됩니다. 미디어/오류 최종 응답은 대기 중인 미리보기 편집을 취소하고 일회성 미리보기 게시물을 플러시하는 대신 일반 전달을 사용합니다.

    channels.mattermost.streaming으로 활성화:

    {
      channels: {
        mattermost: {
          streaming: "partial", // off | partial | block | progress
        },
      },
    }
    
    Streaming modes
    • partial은 일반적인 선택입니다. 답글이 길어질수록 편집되는 하나의 미리보기 게시물을 사용한 뒤, 완전한 답변으로 최종화합니다.
    • block은 미리보기 게시물 안에서 추가 방식의 초안 청크를 사용합니다.
    • progress는 생성 중 상태 미리보기를 표시하고 완료 시 최종 답변만 게시합니다.
    • off는 미리보기 스트리밍을 비활성화합니다.
    Streaming behavior notes
    • 스트림을 제자리에서 최종화할 수 없는 경우(예: 스트림 중간에 게시물이 삭제됨), OpenClaw는 답글이 손실되지 않도록 새 최종 게시물을 보내는 방식으로 대체합니다.
    • 추론 전용 페이로드는 > Reasoning: 블록 인용으로 도착하는 텍스트를 포함하여 채널 게시물에서 억제됩니다. 다른 표면에서 사고 과정을 보려면 /reasoning on을 설정하세요. Mattermost 최종 게시물은 답변만 유지합니다.
    • 채널 매핑 매트릭스는 Streaming을 참조하세요.

    반응(메시지 도구)

    • message action=reactchannel=mattermost와 함께 사용합니다.
    • messageId는 Mattermost 게시물 ID입니다.
    • emojithumbsup 또는 :+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"],
        },
      },
    }
    

    buttons 매개변수와 함께 message action=send를 사용합니다. 버튼은 2D 배열(버튼 행)입니다.

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

    버튼 필드:

    textstringrequired

    표시 레이블입니다.

    callback_datastringrequired

    클릭 시 다시 전송되는 값입니다(작업 ID로 사용됨).

    style"default" | "primary" | "danger"

    버튼 스타일입니다.

    사용자가 버튼을 클릭하면:

  • 버튼이 확인 메시지로 대체됨

    모든 버튼이 확인 줄로 대체됩니다(예: "✓ Yes selected by @user").

  • 에이전트가 선택을 수신함

    에이전트는 선택을 인바운드 메시지로 수신하고 응답합니다.

  • 구현 참고 사항
    • 버튼 콜백은 HMAC-SHA256 검증을 사용합니다(자동, 설정 필요 없음).
    • Mattermost는 API 응답에서 콜백 데이터를 제거하므로(보안 기능), 클릭 시 모든 버튼이 제거됩니다. 부분 제거는 불가능합니다.
    • 하이픈이나 밑줄이 포함된 작업 ID는 자동으로 정리됩니다(Mattermost 라우팅 제한).
    설정 및 도달 가능성
    • channels.mattermost.capabilities: 기능 문자열 배열입니다. 에이전트 시스템 프롬프트에서 버튼 도구 설명을 활성화하려면 "inlineButtons"를 추가하세요.
    • 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은 에이전트의 message 도구를 거치지 않고 Mattermost REST API를 통해 버튼을 직접 게시할 수 있습니다. 가능하면 Plugin의 buildButtonAttachments()를 사용하세요. 원시 JSON을 게시하는 경우 다음 규칙을 따르세요:

    페이로드 구조:

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

    HMAC 토큰 생성

    Gateway는 HMAC-SHA256으로 버튼 클릭을 검증합니다. 외부 스크립트는 Gateway의 검증 로직과 일치하는 토큰을 생성해야 합니다:

  • 봇 토큰에서 비밀값 파생

    HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)

  • 컨텍스트 객체 구성

    _token제외한 모든 필드로 컨텍스트 객체를 구성합니다.

  • 정렬된 키로 직렬화

    정렬된 키공백 없음으로 직렬화합니다(Gateway는 정렬된 키로 JSON.stringify를 사용하며, 이는 압축된 출력을 생성합니다).

  • 페이로드 서명

    HMAC-SHA256(key=secret, data=serializedContext)

  • 토큰 추가

    결과 hex digest를 컨텍스트의 _token으로 추가합니다.

  • Python 예시:

    
    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는 페이로드를 저장할 때 컨텍스트 필드를 재정렬할 수 있습니다.
    • 비밀값은 임의 바이트가 아니라 봇 토큰에서 파생하세요(결정적). 비밀값은 버튼을 생성하는 프로세스와 검증하는 Gateway에서 동일해야 합니다.

    디렉터리 어댑터

    Mattermost Plugin에는 Mattermost API를 통해 채널 및 사용자 이름을 확인하는 디렉터리 어댑터가 포함되어 있습니다. 이를 통해 openclaw message send 및 Cron/Webhook 전달에서 #channel-name@username 대상을 사용할 수 있습니다.

    설정은 필요하지 않습니다. 어댑터는 계정 설정의 봇 토큰을 사용합니다.

    다중 계정

    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"를 설정하세요.

    인증 또는 다중 계정 오류
    • 봇 토큰, 기본 URL, 계정이 활성화되어 있는지 확인하세요.
    • 다중 계정 문제: 환경 변수는 default 계정에만 적용됩니다.
    네이티브 슬래시 명령 실패
    • Unauthorized: invalid command token.: OpenClaw가 콜백 토큰을 수락하지 않았습니다. 일반적인 원인:
      • 슬래시 명령 등록이 시작 시 실패했거나 부분적으로만 완료됨
      • 콜백이 잘못된 Gateway/계정에 도달하고 있음
      • Mattermost에 이전 콜백 대상을 가리키는 오래된 명령이 아직 남아 있음
      • Gateway가 슬래시 명령을 다시 활성화하지 않고 재시작됨
    • 네이티브 슬래시 명령이 작동을 멈추면 로그에서 mattermost: failed to register slash commands 또는 mattermost: native slash commands enabled but no commands could be registered를 확인하세요.
    • callbackUrl이 생략되어 있고 로그에 콜백이 http://127.0.0.1:18789/...로 확인되었다는 경고가 표시되면, 해당 URL은 Mattermost가 OpenClaw와 같은 호스트/네트워크 네임스페이스에서 실행될 때만 도달 가능할 가능성이 큽니다. 대신 명시적으로 외부에서 도달 가능한 commands.callbackUrl을 설정하세요.
    버튼 문제
    • 버튼이 흰색 상자로 표시됨: 에이전트가 잘못된 형식의 버튼 데이터를 보내고 있을 수 있습니다. 각 버튼에 textcallback_data 필드가 모두 있는지 확인하세요.
    • 버튼은 렌더링되지만 클릭해도 아무 동작이 없음: Mattermost 서버 설정의 AllowedUntrustedInternalConnections127.0.0.1 localhost가 포함되어 있고, ServiceSettings에서 EnablePostActionIntegrationtrue인지 확인하세요.
    • 클릭 시 버튼이 404를 반환함: 버튼 id에 하이픈이나 밑줄이 포함되어 있을 가능성이 큽니다. Mattermost의 작업 라우터는 영숫자가 아닌 ID에서 깨집니다. [a-zA-Z0-9]만 사용하세요.
    • Gateway 로그에 invalid _token이 표시됨: HMAC 불일치입니다. 모든 컨텍스트 필드(일부가 아님)에 서명했는지, 정렬된 키를 사용하는지, 압축 JSON(공백 없음)을 사용하는지 확인하세요. 위의 HMAC 섹션을 참조하세요.
    • Gateway 로그에 missing _token in context가 표시됨: _token 필드가 버튼의 컨텍스트에 없습니다. 통합 페이로드를 구성할 때 포함되었는지 확인하세요.
    • 확인 메시지에 버튼 이름 대신 원시 ID가 표시됨: context.action_id가 버튼의 id와 일치하지 않습니다. 둘 다 동일하게 정리된 값으로 설정하세요.
    • 에이전트가 버튼을 알지 못함: Mattermost 채널 설정에 capabilities: ["inlineButtons"]를 추가하세요.

    관련 항목