Files
Ayaan Gazali 1f2e99832b fix(channels): bundled channels reject the documented responsePrefix override (#118148)
* fix(channels): bundled channels reject the documented responsePrefix override

* fix(feishu): pass channel and account to the reply prefix resolver

The ordinary reply dispatcher built the prefix context without channel or
accountId, so channels.feishu.responsePrefix and its account override fell
through to the global value. The comment dispatcher already passed them.

* fix(channels): accept twitch's root responsePrefix and type ClickClack's

Twitch validates as a two-branch union with both branches closed, so
responsePrefix declared only on the account shape left
channels.twitch.responsePrefix rejected whenever accounts is present. Also
declares responsePrefix on ClickClackAccountConfig so typed callers can express
what its schema already accepts.

* fix(clickclack): apply the configured responsePrefix in model mode

Model mode sends the completion straight to ClickClack instead of going through
the agent reply pipeline, so the documented responsePrefix parsed and then did
nothing. Resolve it through the public reply-pipeline seam so template
variables like {model} render from the completion's own provider and model.

* fix(clickclack): do not double the response prefix in model mode

systemPrompt is operator-owned, so a model can be instructed to emit the
configured prefix itself and the unconditional concatenation then sent it
twice. Match the shared reply normalizer's startsWith guard.

* test(clickclack): resolve inbound access through the real resolver

Main now requires access.channelIngress, which the hand-built fixture did not
provide, so the model-mode messages never dispatched. Drop the fixture and let
handleClickClackInbound resolve access from a DM-shaped message, matching the
sibling bot-loop tests.

* test(channels): reject a key missing from any composed branch

A union alternative is a configuration mode an operator can pick, so a key
present in only one mode is unusable in the other even though the union still
validates. Treat any rejecting alternative as a rejection, and walk allOf when
collecting account schemas.

* fix(channels): offer responsePrefix only where the reply path applies it

Applying the prefix to an outbound reply is per-channel wiring, not a shared
step. Buzz, Nostr, QA Channel, Raft, Reef and SMS never read it, so accepting
the key there validated a setting their delivery path ignores. Anchor the
contract to the channels that consume the prefix.

* fix(channels): complete shared response prefix delivery

Co-authored-by: ayaangazali <ayaangazali.work@gmail.com>

* docs(config): refresh response prefix baseline

* test(tlon): use canonical prefix fixture helpers

* test(channels): prove Twitch reply prefix delivery

Exercise schema admission and the real shared reply dispatcher at the Twitch native send boundary, replacing redundant schema-only coverage. Keep Tlon fixtures on canonical imports and recording options.

* docs(channels): clarify explicit message prefix behavior

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 17:08:28 -07:00
..

@openclaw/twitch

Twitch channel plugin for OpenClaw.

Install (local checkout)

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

Install (npm)

openclaw plugins install @openclaw/twitch

Onboarding: select Twitch and confirm the install prompt to fetch the plugin automatically.

Config

Minimal config (simplified single-account):

⚠️ Important: requireMention defaults to true. Add access control (allowFrom or allowedRoles) to prevent unauthorized users from triggering the bot.

{
  channels: {
    twitch: {
      enabled: true,
      username: "openclaw",
      accessToken: "oauth:abc123...", // OAuth Access Token (add oauth: prefix)
      clientId: "xyz789...", // Client ID from Token Generator
      channel: "vevisk", // Channel to join (required)
      allowFrom: ["123456789"], // (recommended) Your Twitch user ID only (Convert your twitch username to ID at https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/)
    },
  },
}

Access control options:

  • requireMention: false - Disable the default mention requirement to respond to all messages
  • allowFrom: ["your_user_id"] - Restrict to your Twitch user ID only (find your ID at https://www.twitchangles.com/xqc or similar)
  • allowedRoles: ["moderator", "vip", "subscriber"] - Restrict to specific roles

Multi-account config (advanced):

{
  channels: {
    twitch: {
      enabled: true,
      accounts: {
        default: {
          username: "openclaw",
          accessToken: "oauth:abc123...",
          clientId: "xyz789...",
          channel: "vevisk",
        },
        channel2: {
          username: "openclaw",
          accessToken: "oauth:def456...",
          clientId: "uvw012...",
          channel: "secondchannel",
        },
      },
    },
  },
}

Setup

  1. Create a dedicated Twitch account for the bot, then generate credentials: Twitch Token Generator
    • Select Bot Token
    • Verify scopes chat:read and chat:write are selected
    • Copy the Access Token to token property
    • Copy the Client ID to clientId property
  2. Start the gateway

Full documentation

See https://docs.openclaw.ai/channels/twitch for:

  • Token refresh setup
  • Access control patterns
  • Multi-account configuration
  • Troubleshooting
  • Capabilities & limits