Chat Transport

Summary

Chat transport is the Phase 5b feature that connects Twitch and YouTube live chat to the GoLiveBro chatbot runtime, enabling chat-driven scene switching in OBS. The system follows a server-side evaluation architecture: the Go control plane receives chat messages from Twitch (via EventSub webhook conduit) and YouTube (via liveChatMessages polling), evaluates commands against the user’s chatbot config, sends bot replies immediately through platform APIs, and queues scene-switch commands for the OBS plugin to pick up via a lightweight 1.5-second command poll endpoint.

The design was developed across three planning phases over three consecutive days (2026-03-25 to 2026-03-27). The initial design on March 25 established the core architecture, including the internal/chat/ Go package with 8 files (evaluator, command queue, config store, Twitch webhook/conduit/sender, YouTube poller/sender). The wiring phase on March 26 defined the end-to-end flow from plugin toggle through backend setup to Twitch EventSub to bot replies and back to the plugin. The conduit persistence phase on March 27 solved the problem of EventSub conduits being lost on server restart by persisting the conduit ID to the database.

The chatbot feature is free for all users with no entitlement check. Twitch is the primary transport using EventSub with a conduit (webhook transport, up to 20,000 shards). YouTube uses polling with a critical quota constraint of 10,000 API units/day (each poll costs 5 units). The TelemyBot sends replies on Twitch as its own identity, but on YouTube, replies are sent as the user since YouTube lacks a bot-joins-channel model.

Timeline

  • 2026-03-25: Chat transport design approved. Architecture decisions finalized: server-side evaluation over relay-to-plugin, single central server (chat latency tolerance is seconds), same containers as existing services (no new service), Twitch EventSub conduit over legacy IRC.
  • 2026-03-25: Implementation plan created. 8 tasks across 2 phases (Phase A: core chat package, Phase B: endpoints + wiring). Tech stack: Go with chi router, nicklaw5/helix for Twitch API, YouTube Data API v3, PostgreSQL.
  • 2026-03-26: Chat wiring design approved. Defined POST /api/v1/chat/config endpoint, first-enable logic (bot-add via Helix API, conduit+subscription creation), disable semantics, auto-scene announcement endpoint, C++ plugin changes, dock UI changes.
  • 2026-03-26: Chat wiring implementation plan created. 4 tasks: store CRUD for chat_subscriptions, bot-add helper, ConfigStore enabled/role fields, handleChatConfig endpoint.
  • 2026-03-27: Conduit persistence design approved. New eventsub_conduit_state table (migration 0026) to persist Twitch EventSub conduit ID across API restarts.
  • 2026-03-27: Conduit persistence implementation plan created. 6 tasks: migration, store methods, EventSubManager.SetConduitID, startup restoration in NewRouter, persist on toggle, verification.

Current State

The chat transport system is implemented with Twitch as the primary supported platform. The Go internal/chat/ package contains the command evaluator (ported from C++ ChatbotRuntime), in-memory per-user command queue (30-second TTL), config store (synced from plugin heartbeats), EventSub conduit manager, Twitch webhook receiver with HMAC-SHA256 signature verification, and Helix chat message sender. The conduit ID is persisted in the eventsub_conduit_state table so webhooks survive server restarts without manual toggle.

API endpoints:

  • POST /api/v1/chat/config (JWT) — enable/disable chatbot, creates EventSub subscription on first enable
  • POST /api/v1/chat/twitch/webhook (HMAC) — Twitch EventSub receiver
  • GET /api/v1/chat/pending (JWT) — command poll for OBS plugin (1.5s interval)
  • POST /api/v1/chat/announce (JWT) — auto-scene announcements from plugin

Database tables: chat_subscriptions (migration 0024), eventsub_conduit_state (migration 0026). The command evaluator supports: status queries, scene switch by alias, scene switch by direct name (!telemy scene Main Camera), auto-resume, broadcaster-only / moderator / everyone role filtering, and an AllowedRole field with BroadcasterOnly backward compatibility.

YouTube transport is designed but quota-constrained: 10,000 units/day allows approximately 2,000 polls total, which would exhaust in about 1 hour at 5-second intervals for a single stream. Google API quota extension is planned as a prerequisite.

Key Decisions

  • 2026-03-25: Server-side command evaluation instead of relaying all chat to the plugin. Bot reply is instant (server to Twitch API), plugin only acts on scene switches, works even if OBS is temporarily disconnected.
  • 2026-03-25: Single central server for chat (not regional). Chat latency tolerance is seconds; cross-Pacific round-trip adds approximately 150ms. Regional servers only needed for SRT video relay.
  • 2026-03-25: Same containers (telemy-api and telemy-jobs) instead of a new service. Current Advin server (4 CPU, 8GB RAM, 90% idle) can handle 500+ chatbot users.
  • 2026-03-25: Twitch EventSub conduit (webhook transport) over IRC. IRC is legacy; Twitch recommends EventSub for new development. 1 conduit with 2-3 shards handles thousands of users.
  • 2026-03-26: Channel is always the authenticated user’s own Twitch channel (no free-text channel input) to prevent trolling.
  • 2026-03-26: Toggle ON first time performs heavy setup (bot-add, conduit, subscription). Toggle OFF/ON after is a lightweight flag flip. Disable sets ConfigStore enabled=false but keeps subscription active and bot in channel.
  • 2026-03-26: No entitlement check. Chatbot is free for all users.
  • 2026-03-27: Persist conduit ID to database to eliminate manual toggle requirement after server restarts. Non-fatal on startup failure (server starts regardless).

Gotchas & Known Issues

  • YouTube API quota is severely limiting: 10,000 units/day allows approximately 2,000 polls total. A Google API quota extension request is required before YouTube transport is viable in production.
  • YouTube replies are sent as the user (not a bot account) because YouTube lacks a bot-joins-channel model. Requires user’s OAuth token with youtube.force-ssl scope.
  • Bot token refresh happens in-memory on 401. Broadcaster token refresh updates the DB. If Twitch revokes a token, the bot stops replying and the user must re-link their account.
  • In-memory command queue means commands are lost on server restart. Commands expire after 30 seconds if not picked up by the plugin.
  • In-memory chatbot config store is synced from plugin heartbeats. No DB persistence for config. Config is authoritative in the plugin.
  • Re-linking to a different Twitch account requires cleanup of stale subscriptions for the old channel_id.
  • Rate limits: POST /chat/config at 10/min per-action, POST /chat/announce at 5/min per user, dock toggle has 3-second UI debounce.
  • Environment variables use TELEMY_ prefix (8 new env vars for bot credentials and EventSub secret). Not yet migrated to GLB_ prefix.

Open Questions

  • When will Google API quota extension be requested for YouTube transport production use?
  • When will the environment variables be migrated from TELEMY_ to GLB_ prefix?
  • At what user count will Redis/in-memory cache be needed for config lookups (scaling trigger: 500+ concurrent chatbot users)?
  • Will long-polling replace the 1.5-second command poll when request volume exceeds 2,000 req/s?
  • YouTube streamList gRPC streaming is mentioned as a future optimization to replace polling. No timeline set.

Sources