Runtime exports remain the single source of truth but are not yet wired to the dashboard UI or any live chat socket feeds. Chat and overlay surfaces render preview/mock data until runtime plumbing is connected.
- Project Status: Late alpha (v0.2.3-alpha, Build 2025.04). Runtime execution is preserved for export generation; dashboard UI remains a separate repository and is not coupled at runtime.
- Runtime ↔ Dashboard separation: This repo owns the Runtime Engine. Dashboard UI lives in a different repo and only consumes exported artifacts; no UI elements initiate runtime execution.
- What is live: Export generation, schemas, and historical scaffolding. Existing exports stay authoritative for read-only inspection.
- Not live yet: Chat runtime plumbing, live chat socket ingestion, OBS overlay feeds, and browser extension hydration remain preview-only and have no active runtime wiring.
- Ownership boundary: The runtime continues to guard data-plane correctness; dashboards, overlays, and extensions must remain read-only and avoid mutation paths.
StreamSuites is a modular, multi-platform livestream automation system. It is the single canonical runtime source for orchestrating streaming data-plane workers and control-plane automation across platforms such as Discord, YouTube, Twitch, Twitter/X, and Rumble. Tallies are now tracked as a first-class runtime concept alongside polls and clips, with schema-only scaffolding in place for future dashboard/public visibility.
- Current version: v0.2.3-alpha (Build 2025.04)
- Development stage: Late Alpha — features are present but still undergoing hardening, observability work, and lifecycle tightening before beta stabilization.
- Versioning policy: Semantic Versioning with pre-release tags (e.g.,
-alpha,-beta) to signal stability and readiness. Pre-release identifiers reflect runtime maturity and do not guarantee API permanence. - Authoritative runtime: This repository is the authoritative runtime source of truth for StreamSuites. Dashboard and external consumers are strictly read-only and must not mutate runtime-managed state.
- Runtime/UI separation: The dashboard UI (separate repo) is not yet connected to runtime execution paths; it consumes published exports only.
- Export-driven UI surfaces: Runtime publishes state via file-based exports (JSON snapshots and HTML replay templates). Dashboards/overlays are expected to read these artifacts without introducing their own write paths.
- Licensing notice: Proprietary. Redistribution or reuse outside authorized channels is not permitted.
- Production readiness: Not production ready. Expect breaking changes, schema adjustments, and operational refinements during the late alpha cycle.
- The StreamSuites Runtime repository is the authoritative home for runtime code, state, telemetry, exports, and changelogs.
- All control-plane and data-plane sources originate here; downstream surfaces must consume artifacts exported from this repo.
- Dashboards and other visualization surfaces are downstream consumers that read runtime-owned exports.
- Location:
desktop-admin/ - Runs locally on the same machine as the runtime and retains direct filesystem access.
- Reads runtime snapshots directly from disk without requiring additional services.
- Can launch and terminate runtime processes from the local control plane.
- Manages local paths and configuration to align runtime exports with operator expectations.
- Intended to become the primary administrative interface over time, ahead of any web dashboard controls.
- The web dashboard lives in a separate repository.
- It consumes runtime-exported JSON artifacts only.
- It has no process control and no filesystem authority.
- It never depends on the WinForms Desktop Admin application.
- It is intentionally less capable by design to preserve runtime integrity.
- VERSION (e.g.,
v0.2.3-alpha): Describes semantic capability level and encapsulates feature, behavior, or contract changes. - BUILD (e.g.,
2025.04): Stamps regenerated artifacts, exports, documentation, and binaries for diagnostics and reproducibility. - Version changes imply meaningful project evolution and should accompany capability or contract adjustments.
- Build changes indicate new artifacts or refreshed exports even when features remain unchanged.
- Runtime: Source of truth for version and build values.
- WinForms Desktop Admin: Reads runtime version/build directly and displays authoritative metadata.
- Web Dashboard: Reads version/build from exported JSON and never defines its own values.
runtime/exports/runtime_snapshot.jsonis the authoritative snapshot export produced by the runtime.- Local Desktop Admin reads snapshot files directly from disk for privileged operations.
- The web dashboard reads published/exported JSON artifacts exclusively and remains read-only.
- Paths may be configured locally via admin tooling to align snapshot locations with operator needs.
The project is built with a strong emphasis on:
- deterministic behavior
- clean lifecycle management
- platform-specific correctness
- future extensibility without architectural rewrites
The first implemented and validated platform was Rumble; Rumble support is currently paused (see status below) but all code remains intact for re-enablement.
core/: streaming runtime entrypoint (app.py), scheduler, job registry, and shared snapshot export loops.services/rumble/: Rumble-specific workers, browser client, SSE client, and chat helpers.shared/: platform-neutral configuration, state publishers, storage helpers, and logging.runtime/: exported snapshots owned by the runtime (state, signals, admin/export manifests).changelog/+scripts/: version stamping and release utilities.services/{twitch,youtube,discord}/: other platform runtimes and control plane implementations.services/kick/: Kick chat scaffold (auth + chat stubs, normalized events, trigger wiring) ready for future scheduler wiring.services/pilled/: Planned ingest-only placeholders for Pilled; no runtime wiring or network calls yet.services/chat_replay/: neutral chat replay scaffolding that ships static, exportable HTML surfaces (pop-out window and OBS overlay) plus a placeholder schema for future replay ingestion; all visuals are mock-data only and avoid live wiring.contracts/chat_message.schema.json: placeholder unified chat replay contract for future ingestion and export validation.templates/chat_replay_window.html: standalone pop-out style chat replay window that renders static mock messages.templates/chat_overlay_obs.html: transparent browser-source overlay for OBS/Meld/Streamlabs with fade-in entries.templates/partials/theme_selector.html: UI stub for swapping bundled chat replay themes without runtime wiring yet.static/chat.css: scoped styling shared by the pop-out and overlay templates.static/themes/: additive theme overrides (theme-default.css,theme-slate.css,theme-midnight.css) that keep avatar sizing consistent across surfaces.static/chat_mock_data.js: labeled placeholder message set used by both templates (no live data yet).README.md: documentation describing the scaffolding purpose and future integration path.- Avatars: circular avatar column is reserved in markup and styles; missing or failed images automatically fall back to
docs/assets/icons/ui/profile.svgso replay operators never ship a broken or empty avatar state.
StreamSuites/
├── .env.example
├── .gitignore
├── .github/
│ └── workflows/
│ └── publish-dashboard-state.yml
├── LICENSE
├── README.md
├── RUNTIME_AUDIT_REPORT.md
├── changelog/
│ ├── README.md
│ └── changelog.runtime.json
├── clips/
│ └── output/
│ └── .gitkeep
├── core/
│ ├── README.md
│ ├── __init__.py
│ ├── app.py
│ ├── config_loader.py
│ ├── context.py
│ ├── discord_app.py
│ ├── jobs.py
│ ├── ratelimits.py
│ ├── registry.py
│ ├── scheduler.py
│ ├── state_exporter.py
│ ├── shutdown.py
│ ├── signals.py
│ └── tallies/
│ ├── README.md
│ ├── __init__.py
│ └── models.py
├── data/
│ └── streamsuites.db
├── desktop-admin/
│ ├── StreamSuites.DesktopAdmin.sln
│ ├── StreamSuites.DesktopAdmin/
│ │ ├── App.config
│ │ ├── MainForm.Designer.cs
│ │ ├── MainForm.cs
│ │ ├── MainForm.resx
│ │ ├── Program.cs
│ │ ├── StreamSuites.DesktopAdmin.csproj
│ │ ├── StreamSuites.DesktopAdmin.csproj.user
│ │ └── assets/
│ │ ├── discord-0.svg
│ │ ├── discord-muted.svg
│ │ ├── discord.png
│ │ ├── discord.svg
│ │ ├── kick-0.svg
│ │ ├── kick-muted.svg
│ │ ├── kick.png
│ │ ├── kick.svg
│ │ ├── pilled-0.svg
│ │ ├── pilled-muted.svg
│ │ ├── pilled.png
│ │ ├── pilled.svg
│ │ ├── rumble-0.svg
│ │ ├── rumble-muted.svg
│ │ ├── rumble.png
│ │ ├── rumble.svg
│ │ ├── streamsuites.ico
│ │ ├── twitch-0.svg
│ │ ├── twitch-muted.svg
│ │ ├── twitch.png
│ │ ├── twitch.svg
│ │ ├── twitter-0.svg
│ │ ├── twitter-muted.svg
│ │ ├── twitter.svg
│ │ ├── youtube-0.svg
│ │ ├── youtube-muted.svg
│ │ ├── youtube.png
│ │ └── youtube.svg
│ ├── StreamSuites.DesktopAdmin.Core/
│ │ ├── AppState.cs
│ │ ├── ModeContext.cs
│ │ ├── PathConfigService.cs
│ │ └── StreamSuites.DesktopAdmin.Core.csproj
│ ├── StreamSuites.DesktopAdmin.Models/
│ │ ├── PlatformStatus.cs
│ │ ├── RuntimeSnapshot.cs
│ │ ├── TelemetrySnapshot.cs
│ │ ├── TriggerCounter.cs
│ │ └── StreamSuites.DesktopAdmin.Models.csproj
│ └── StreamSuites.DesktopAdmin.RuntimeBridge/
│ ├── AdminCommandDispatcher.cs
│ ├── FileSnapshotReader.cs
│ ├── RuntimeConnector.cs
│ └── StreamSuites.DesktopAdmin.RuntimeBridge.csproj
├── desktop-admin/.vs/
│ └── ProjectEvaluation/
│ ├── streamsuites.desktopadmin.metadata.v10.bin
│ ├── streamsuites.desktopadmin.projects.v10.bin
│ └── streamsuites.desktopadmin.strings.v10.bin
├── docs/
│ ├── POST_MORTEM.md
│ └── assets/
│ └── placeholders/
│ ├── daniel-badge.svg
│ ├── daniel.svg
│ ├── hotdog.svg
│ └── streamsuites.svg
├── exports/
│ └── public/
│ └── .gitkeep
├── media/
│ ├── capture/
│ │ ├── rumble.py
│ │ ├── twitch.py
│ │ └── youtube.py
│ ├── jobs/
│ │ ├── base.py
│ │ ├── clip_job.py
│ │ └── upload_job.py
│ ├── processing/
│ │ ├── metadata.py
│ │ ├── transcode.py
│ │ └── trim.py
│ └── storage/
│ ├── buffer.py
│ ├── cleanup.py
│ └── clips.py
├── runtime/
│ ├── admin/
│ │ ├── chat_triggers.json
│ │ ├── creators.json
│ │ ├── integrations.json
│ │ ├── jobs.json
│ │ ├── permissions.json
│ │ └── rate_limits.json
│ ├── exports/
│ │ ├── README.md
│ │ ├── about.admin.json
│ │ ├── about.public.json
│ │ ├── changelog.json
│ │ ├── changelog.runtime.json
│ │ ├── clips.json
│ │ ├── meta.json
│ │ ├── platforms.json
│ │ ├── polls.json
│ │ ├── roadmap.json
│ │ ├── runtime_snapshot.json
│ │ ├── scoreboards.json
│ │ ├── tallies.json
│ │ └── telemetry/
│ │ ├── errors.json
│ │ ├── events.json
│ │ └── rates.json
│ ├── signals/
│ │ ├── chat_events.json
│ │ ├── poll_votes.json
│ │ ├── score_events.json
│ │ └── tally_events.json
│ └── version.py
├── schemas/
│ ├── creators.schema.json
│ ├── platforms.schema.json
│ ├── system.schema.json
│ └── triggers.schema.json
├── scripts/
│ ├── bootstrap.py
│ ├── publish_state.py
│ ├── update_version.py
│ └── validate_config.py
├── services/
│ ├── chat_replay/
│ │ ├── README.md
│ │ ├── contracts/
│ │ │ └── chat_message.schema.json
│ │ ├── static/
│ │ │ ├── chat.css
│ │ │ ├── chat_live_input.css
│ │ │ ├── chat_mock_data.js
│ │ │ └── themes/
│ │ │ ├── theme-default.css
│ │ │ ├── theme-midnight.css
│ │ │ └── theme-slate.css
│ │ └── templates/
│ │ ├── chat_overlay_obs.html
│ │ ├── chat_replay_window.html
│ │ ├── chat_window.html
│ │ └── partials/
│ │ ├── footer_live.html
│ │ ├── footer_replay.html
│ │ ├── theme_menu.html
│ │ └── theme_selector.html
│ ├── clips/
│ │ ├── __init__.py
│ │ ├── encoder.py
│ │ ├── exporter.py
│ │ ├── manager.py
│ │ ├── models.py
│ │ ├── storage.py
│ │ ├── uploader.py
│ │ └── worker.py
│ ├── discord/
│ │ ├── README.md
│ │ ├── announcements.py
│ │ ├── client.py
│ │ ├── commands/
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── admin_commands.py
│ │ │ ├── creators.py
│ │ │ ├── public.py
│ │ │ └── services.py
│ │ ├── heartbeat.py
│ │ ├── logging.py
│ │ ├── permissions.py
│ │ ├── runtime/
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── lifecycle.py
│ │ │ └── supervisor.py
│ │ ├── status.py
│ │ └── tasks/
│ │ ├── README.md
│ │ ├── pilled_live.py
│ │ ├── rumble_live.py
│ │ ├── twitch_live.py
│ │ ├── twitter_posting.py
│ │ └── youtube_live.py
│ ├── kick/
│ │ ├── __init__.py
│ │ ├── README.md
│ │ ├── api/
│ │ │ ├── __init__.py
│ │ │ └── chat.py
│ │ ├── models/
│ │ │ ├── __init__.py
│ │ │ └── message.py
│ │ └── workers/
│ │ ├── __init__.py
│ │ ├── chat_worker.py
│ │ └── livestream_worker.py
│ ├── pilled/
│ │ ├── README.md
│ │ └── api/
│ │ ├── chat.py
│ │ └── livestream.py
│ ├── rumble/
│ │ ├── api/
│ │ │ ├── channel_page.py
│ │ │ ├── chat.py
│ │ │ └── chat_post.py
│ │ ├── browser/
│ │ │ ├── __init__.py
│ │ │ └── browser_client.py
│ │ ├── chat/
│ │ │ ├── rest_client.py
│ │ │ ├── sse.py
│ │ │ └── tombi_stream.py
│ │ ├── chat_client.py
│ │ ├── models/
│ │ │ ├── chat_event.py
│ │ │ ├── message.py
│ │ │ └── stream.py
│ │ └── workers/
│ │ ├── chat_worker.py
│ │ └── livestream_worker.py
│ ├── triggers/
│ │ ├── __init__.py
│ │ ├── actions.py
│ │ ├── base.py
│ │ ├── README.md
│ │ ├── registry.py
│ │ └── validation.py
│ ├── twitch/
│ │ ├── README.md
│ │ ├── api/
│ │ │ ├── chat.py
│ │ │ └── livestream.py
│ │ ├── models/
│ │ │ └── message.py
│ │ └── workers/
│ │ └── chat_worker.py
│ ├── twitter/
│ │ ├── api/
│ │ │ ├── auth.py
│ │ │ └── posting.py
│ │ └── workers/
│ │ └── posting_worker.py
│ └── youtube/
│ ├── README.md
│ ├── api/
│ │ ├── chat.py
│ │ └── livestream.py
│ ├── models/
│ │ ├── message.py
│ │ └── stream.py
│ └── workers/
│ ├── chat_worker.py
│ └── livestream_worker.py
├── shared/
│ ├── config/
│ │ ├── chat_behaviour.json
│ │ ├── clip_rules.json
│ │ ├── creators.json
│ │ ├── logging.json
│ │ ├── monetization.json
│ │ ├── posting_rules.json
│ │ ├── ratelimits.json
│ │ ├── services.json
│ │ ├── services.py
│ │ ├── system.json
│ │ ├── system.py
│ │ ├── tiers.json
│ │ └── triggers.json
│ ├── logging/
│ │ ├── levels.py
│ │ └── logger.py
│ ├── platforms/
│ │ ├── __init__.py
│ │ └── state.py
│ ├── public_exports/
│ │ ├── __init__.py
│ │ ├── clips.py
│ │ ├── polls.py
│ │ └── publisher.py
│ ├── ratelimiter/
│ │ └── governor.py
│ ├── runtime/
│ │ ├── __init__.py
│ │ ├── admin_contract.py
│ │ ├── quotas.py
│ │ ├── quotas_snapshot.py
│ │ ├── hot_reload.py
│ │ └── scoreboards_snapshot.py
│ ├── scoreboards/
│ │ ├── README.md
│ │ ├── placeholders.py
│ │ ├── registry.py
│ │ ├── schema.json
│ │ └── snapshot.py
│ ├── state/
│ │ ├── chat_logs/
│ │ │ └── .gitkeep
│ │ ├── creators/
│ │ │ └── daniel.json
│ │ ├── discord/
│ │ │ ├── README.md
│ │ │ └── runtime.json
│ │ ├── jobs.json
│ │ ├── quotas.json
│ │ ├── scoreboards/
│ │ │ └── .gitkeep
│ │ └── system.json
│ ├── storage/
│ │ ├── chat_events/
│ │ │ ├── __init__.py
│ │ │ ├── index.py
│ │ │ ├── reader.py
│ │ │ ├── schema.json
│ │ │ └── writer.py
│ │ ├── file_lock.py
│ │ ├── paths.py
│ │ ├── scoreboards/
│ │ │ ├── README.md
│ │ │ ├── exporter.py
│ │ │ └── importer.py
│ │ ├── state_publisher.py
│ │ └── state_store.py
│ └── utils/
│ ├── files.py
│ ├── hashing.py
│ ├── retry.py
│ └── time.py
├── tests/
│ └── __init__.py
├── requirements.txt
├── rumble_chat_poc.py
├── rumble_poc/
├── twitch_chat_poc.py
└── test_rumble_api.py
StreamSuites Desktop Admin is a WinForms-based administrator console that reads
runtime-exported snapshots and surfaces platform health, platform enablement,
and telemetry freshness in a native desktop experience. The admin app uses a
Runtime Bridge layer (StreamSuites.DesktopAdmin.RuntimeBridge) to read
runtime_snapshot.json from the runtime's export directory and projects the
data into a grid with tray-aware health indicators, per-platform inspectors,
and configurable refresh cadences.
- Purpose: give operators a lightweight desktop UI that mirrors runtime
exports without adding new mutation paths. Snapshot reading is isolated in the
Runtime Bridge (
FileSnapshotReader+RuntimeConnector), and all computations are held inStreamSuites.DesktopAdmin.Core(AppState,ModeContext). - Runtime interaction: reads snapshot files written by the Python runtime; no direct sockets or API calls are required. Platform counts, staleness thresholds, and snapshot metadata are displayed inline with color-coded health badges and a tray icon.
- Progress:
[██████░░░░]Snapshot reading, grid rendering, and health/tray surfacing are live. Runtime lifecycle controls (reserved inRuntimeExecutablePath) are staged for a later milestone.
- Start the runtime exports loop: launch the Python runtime so it keeps
writing
runtime/exports/runtime_snapshot.json(for examplepython -m core.appor the scheduler entrypoint used in your environment). - Point Desktop Admin at the snapshot directory: update
desktop-admin/StreamSuites.DesktopAdmin/App.configSnapshotDirectoryto the absolute path of the runtime export root (e.g., theruntime/exportsdirectory in this repo or a published dashboard checkout such as../StreamSuites-Dashboard/docs/shared/state). The default file name remainsruntime_snapshot.jsonbut can be overridden viaSnapshotFileName. - Build and run the WinForms app: open
desktop-admin/StreamSuites.DesktopAdmin.slnin Visual Studio on Windows and run theStreamSuites.DesktopAdminproject. The app will refresh snapshots on the interval defined bySnapshotRefreshIntervalMsand mark stale states usingSnapshotStaleAfterSeconds.
When both processes are active, the desktop admin presents live platform and telemetry status sourced from the runtime exports while keeping the runtime the sole authority for state changes.
- SSE_BEST_EFFORT (default): connects to
https://web7.rumble.com/chat/api/chat/<CHAT_ID>/streamwith the live browser cookies/headers. HTTP 204 responses are treated as keepalives, not failures, and do not trigger exponential backoff. Onlytext/event-streampayloads are parsed; non-SSE responses cap retries and cause a downgrade. - DOM_MUTATION (authoritative fallback): attaches a MutationObserver inside the chat iframe to capture newly added message nodes. Each captured node is normalized into the runtime message record (username, text, timestamp when present) so ingest stays deterministic even when the SSE endpoint is silent or blocked. This mode is activated automatically when SSE stays quiet beyond the configured window or explicitly fails to connect.
- DISABLED: terminal state used when no ingest path can be attached (e.g., chat iframe missing). The worker logs the disabled state but keeps the process alive.
The worker logs the active ingest mode at startup and every downgrade event. DOM send remains isolated and continues regardless of ingest path.
- Iframe-scoped DOM send: outbound chat messages target the chat iframe
directly. The bot focuses
#chat-message-text-input, dispatches React-safe DOM events, and clicks thebutton.chat--sendcontrol. Enter is never pressed to avoid monetization modals or key-capture side effects. - Payment / monetization guard: known Rumble monetization modals are detected and closed before sending. All selectors used for sending are logged for observability and the send will abort (not fall back to Enter) if required elements are missing.
- No REST chat sends: outbound chat remains DOM-driven; no REST chat send endpoints are used.
Rumble chat handling is split into two independent, cooperating paths so that send reliability is preserved even when ingest requirements change:
- DOM send (Playwright): authenticated browser session drives the chat input and button click. This path relies on Playwright only and is unaffected by SSE headers or cookies.
- SSE ingest (httpx): authoritative read path that mirrors the browser
session. The SSE request must include the browser's cookies, user-agent,
Origin
https://rumble.com, and Referer set to the livestream watch URL. Missing any of these headers causes Rumble to return HTTP 204 withcontent-type=text/html, which prevents events from flowing.
- Rumble's SSE endpoint validates the authenticated session using both cookies and CSRF-style headers derived from the browser context. Cookies alone no longer authorize the stream, and requests without the proper User-Agent, Origin, and Referer are rejected with empty responses.
- The runtime now exports cookies directly from the Playwright context and
injects them as both structured cookie jars and
Cookieheaders to match the browser.
- A 204 response with
content-type=text/htmloften means the server is not ready to emit events yet. The runtime now treats these as keepalives rather than failures and holds the connection without exponential backoff. Only repeated non-SSE responses or stream errors trigger a downgrade to the DOM mutation ingest path.
- Rumble SSE availability is environment-dependent; repeated non-SSE responses will trigger a downgrade to DOM mutation ingest while HTTP 204 responses are treated as keepalives.
- A logged-in Rumble profile is still required in the persistent Playwright context before runtime start.
- DOM chat sending requires the chat iframe (
#chat-message-text-inputandbutton.chat--send) to be present; if Rumble ships DOM changes, selectors may need to be updated before send succeeds. - Baseline cutoffs prefer DOM-visible timestamps; if both DOM and the
livestream API are unreachable, the worker falls back to
now()without crashing and keeps ingest mode stateful. - APIRequestContext is intentionally avoided during ingest to prevent TLS/X509
crashes and cross-talk with the Playwright automation session; HTTP calls use
isolated
httpxclients with browser-derived cookies/headers instead.
- Status: Alpha preview, export-driven. Runtime stays authoritative for data snapshots but is not yet connected to the dashboard UI or any live chat socket feeds.
- Current snapshot: v0.2.3-alpha (Build 2025.04) remains the active late-alpha reference state.
- Operational impact: chat runtime plumbing, live socket ingestion, and overlay feeds are not live; dashboard and overlay views are preview-only and rely on exported/mock data.
- Dashboard and exports: schemas and exports continue to be maintained for read-only consumption; UI consumers must not assume live connectivity until runtime wiring is delivered.
The runtime is the authoritative data source, signal processor, and
export generator for the Data & Signals dashboard. It owns raw events and
controls how they are shaped for consumption while keeping dashboard access
strictly read-only. Snapshot files under runtime/exports/, runtime/signals/,
and runtime/admin/ are deterministic, timestamped JSON documents that can be
mirrored into the dashboard repository or any static host. The dashboard never
mutates runtime state; it only reads the published snapshots.
- Authoritative data source: runtime workers own the canonical state for clips, polls, tallies, scoreboards, creators, and quotas.
- Signal processor: normalized chat, poll, tally, and score events are captured for dashboard inspection without enabling writes or action execution.
- Export generator: deterministic JSON snapshots are produced for public galleries, dashboard-only operations, and internal integration surfaces.
- Telemetry snapshots:
runtime/exports/telemetry/surfaces read-only operational events, rolling rate aggregates, and trimmed error records so the dashboard can poll live health signals from static hosting surfaces.
- Source of truth:
runtime/version.pyremains the canonical version declaration. All downstream JSON surfaces derive from this value. - Changelog + roadmap alignment:
scripts/update_version.pystamps the runtime version acrosschangelog/changelog.runtime.json, exported changelog files, and the dashboardversion.jsonmanifest when available. - About documentation: the runtime owns version stamping for the
dashboard's JSON-driven About content (e.g.,
docs/about/about_part*.json).scripts/update_version.pyupdates theversionfield for every About JSON document it can find under<dashboard-root>/about/while keeping runtime execution paths free of About dependencies.- Usage:
python scripts/update_version.py v0.2.3-alpha --build 2025.04 --dashboard-root ../StreamSuites-Dashboard/docs - If the dashboard checkout is absent, the script safely skips dashboard updates while keeping runtime metadata in sync.
- Usage:
- Dashboard consumption is read-only. Snapshots are written by the runtime
and optionally mirrored into the dashboard
docs/data/root or another hosting path. - Snapshots include a
metablock with timestamps, source identifiers, and visibility tags (public,dashboard-only,internal-only) so the dashboard can filter without relying on file placement alone. - Future sync paths (e.g., file-based or HTTP) must continue to respect the read-only boundary; no live mutation from dashboard surfaces is permitted.
| File | Location | Visibility | Notes |
|---|---|---|---|
clips.json |
runtime/exports/ |
Public | Published clips snapshot, safe for public galleries. |
polls.json |
runtime/exports/ |
Public | Poll questions + aggregated votes, no voter identifiers. |
tallies.json |
runtime/exports/ |
Public | Aggregate tally counts only. |
scoreboards.json |
runtime/exports/ |
Public | Ranked scoreboard entries with scores. |
meta.json |
runtime/exports/ |
Public | Manifest describing the export surface. |
telemetry/events.json |
runtime/exports/telemetry/ |
Public | High-level runtime events (timestamp, source, severity, message). |
telemetry/rates.json |
runtime/exports/telemetry/ |
Public | Rolling activity counters for chat, triggers, and actions (60s + 5m windows). |
telemetry/errors.json |
runtime/exports/telemetry/ |
Public | Lightweight error records scoped to subsystem/error type without stack traces. |
chat_events.json |
runtime/signals/ |
Dashboard-only | Normalized chat events for inspection. |
poll_votes.json |
runtime/signals/ |
Dashboard-only | Individual poll vote events without personal data. |
tally_events.json |
runtime/signals/ |
Dashboard-only | Increment events for tallies. |
score_events.json |
runtime/signals/ |
Dashboard-only | Score adjustments feeding scoreboards. |
creators.json |
runtime/admin/ |
Dashboard-only | Creator registry snapshot. |
chat_triggers.json |
runtime/admin/ |
Dashboard-only | Trigger definitions for reference only. |
jobs.json |
runtime/admin/ |
Dashboard-only | Job queue visibility (read-only). |
rate_limits.json |
runtime/admin/ |
Dashboard-only | Rate limit policies visible to operators. |
integrations.json |
runtime/admin/ |
Internal-only | Integration endpoints and statuses. |
permissions.json |
runtime/admin/ |
Internal-only | Placeholder for future principal/role mapping. |
- Runtime authors maintain the canonical changelog structure in
changelog/changelog.runtime.json; this file defines the authoritative JSON shape expected by the dashboard. - Exports for distribution live under
runtime/exports/changelog.runtime.jsonand must be produced manually or by CI tooling — the runtime does not emit changelog files during execution. - The dashboard repository merges and renders runtime and dashboard changelog surfaces client-side; no manual merging is required once the export is updated.
- Public changelog views remain a merged surface while the runtime stays authoritative over runtime-originated entries.
- The runtime remains the authoritative source for changelog data, while the dashboard stays read-only and presentational when rendering the merged public surface.
StreamSuites is evolving into a multi-runtime architecture while remaining a single repository. Runtimes are explicitly isolated by responsibility and started by a shared scheduler:
- Streaming runtimes (per platform) live under
core/app.pyand platform services. They own ingestion, publishing, and data-plane orchestration. - The Discord control-plane runtime lives under
core/discord_app.py(standalone entrypoint) and is optionally started by the scheduler. It offers admin/status commands and notification routing without embedding ingestion. - Shared configuration and state live under
shared/, with platform-neutral helpers underservices/. - Rumble Playwright ownership is centralized:
RumbleLivestreamWorkerstarts a single persistent browser instance, andRumbleChatWorkerreuses that page and chat iframe without opening extra tabs.
Both entrypoints are independent runtime processes. The scheduler coordinates lifecycles while keeping control-plane behavior separate from streaming logic.
The runtime owns a deterministic, SQLite-backed clipping module that runs in the background with bounded concurrency. Core properties:
- Purpose: accept clip requests, encode with FFmpeg, upload to a default Rumble destination, and export state for the dashboard.
- Lifecycle states (persisted and exported):
queued,encoding,encoded,uploading,published,failed. - Encoding model: background worker (
services/clips/worker.py) with default concurrency of2(configurable viashared/config/system.json). Output naming is deterministic:clips/output/{clip_id}.mp4withclip_idas a 6-character alphanumeric token. - SQLite usage: tables
clips,clip_jobs, andclip_state_historylive indata/streamsuites.dband are created on boot if missing. State changes are recorded atomically for observability. - FFmpeg dependency: the runtime defaults to
X:\\ffmpeg\\bin\\ffmpeg.exe(Windows-first) and falls back toffmpegon PATH if that path does not exist locally. No auto-installation is attempted. - Export surface: snapshots are written to
shared/state/clips.jsonevery 30 seconds and immediately on state changes, mirroring to the dashboard publish root when configured. - Destination resolution: the default upload target is read dynamically
from
shared/config/system.json(clips.default_destination.channel_url) and currently points tohttps://rumble.com/c/StreamSuites. Architecture permits future per-creator overrides without changing the runtime contract.
- Platform-agnostic trigger registry lives under
services/triggers/. - Triggers evaluate normalized chat events and emit action descriptors (pure data). Execution of any action is intentionally deferred to a later phase.
- Trigger types are design-locked, even when partially scaffolded:
- Command triggers (e.g.,
!clip,!ping) - Regex-based triggers
- Keyword-based triggers
- Cooldowns across user / creator / global scopes
- Command triggers (e.g.,
- The registry is creator-scoped and platform-neutral so chat workers can publish uniformly shaped events without embedding business logic.
- QuotaTracker (enforcement only): in-process daily quota enforcement with buffer + hard-cap handling; tracks usage per creator/platform without writing files or persisting state.
- QuotaRegistry (authoritative, in-memory): global registry that owns all QuotaTrackers for the running process; exposes snapshots for aggregation.
- Snapshot merge: runtime cadence aggregates all registered trackers via
shared/runtime/quotas_snapshot.pyand writes a singleshared/state/quotas.jsondocument throughDashboardStatePublisher(optionally mirrored to the dashboard publish root).
- Runtime ownership: control-plane + streaming runtimes own authoritative
state generation (jobs, triggers, quotas) under
shared/state/and publish viaDashboardStatePublisher. Quota enforcement and cadence loops live only in the runtime. - Dashboard consumption: the dashboard is read-only; it reads published state snapshots (jobs, runtime status, quotas) and never mutates runtime state. Overrides are handled through query parameters and static hosting roots without changing runtime behavior.
The Discord control-plane runtime emits live snapshots for the dashboard under
shared/state/discord/runtime.json (runtime + heartbeat state) and
shared/state/jobs.json (job queue/timestamps). The streaming runtime exports
shared/state/runtime_snapshot.json via core/state_exporter.py, reflecting
platform enablement, telemetry toggles, creator registry status, and recent
heartbeats. Snapshots are written
atomically and can optionally be mirrored into the dashboard hosting root by
setting DASHBOARD_STATE_PUBLISH_ROOT (or STREAMSUITES_STATE_PUBLISH_ROOT)
to the Pages/bucket checkout path. If unset, the runtime will auto-detect a
local ../StreamSuites-Dashboard checkout (docs root) when present. A helper
script is available for cron or CI runs when the runtime is not active:
python scripts/publish_state.py --target ../StreamSuites-Dashboard/docsThe dashboard now resolves state roots in the following order:
stateRootquery parameter (persisted tolocalStorageasstreamsuites.stateRootOverridefor future loads)- The published
./shared/state/directory within the dashboard hosting root - Fallback to the runtime repository's raw URL:
https://raw.githubusercontent.com/BSMediaGroup/StreamSuites/main/shared/state/
To serve snapshots from another host or bucket, open the dashboard with
?stateRoot=<your-url>/ (ensure the trailing slash) and the override will be
remembered. The fallback works only when this repository publishes current
snapshots under shared/state/discord/runtime.json (and optional
shared/state/jobs.json) so the raw GitHub URL always contains valid data.
- Purpose: process-scoped control-plane runtime for operational commands, status surfaces, and notifications. It is not a streaming bot and never launches ingestion workers.
- Modes:
- Standalone:
python -m core.discord_app. - Integrated: started by
core.schedulerwhen Discord is enabled in config.
- Standalone:
- Responsibilities: DiscordClient ownership, DiscordSupervisor lifecycle, heartbeat loop, and shared-state status persistence.
- Separation: does not create its own event loop in integrated mode, does not own scheduler logic, and runs alongside streaming runtimes without coupling shutdown.
- Configuration: feature-gated per creator via
shared/config/creators.jsonplatform flags and runtime settings undershared/config/.
- Application bootstraps environment and creator contexts
- Scheduler launches per-creator runtimes
- Platform workers manage platform-specific logic
- Shared browser and job systems are centrally controlled
- Clean shutdown propagates through all active tasks
+-------------------+
| shared/ config |
+---------+---------+
|
+-------+-------+
| services/ |
+-------+-------+
|
+---------------+---------------+
| |
+------+-------+ +-----+------+
| core/app.py | | core/ |
| (streaming | | discord_ |
| runtime) | | app.py |
+------+-------+ | (Discord |
| | control |
| | plane) |
| +-----+------+
+-----+------+ |
| streaming | | (no ingestion workers)
| workers | |
+------------+ +-----+------+
Discord bots &
control flows
The streaming runtime (core/app.py) continues to operate as a long-running
asynchronous process orchestrated by a central scheduler and composed of
platform-specific workers.
High-level streaming flow:
- Application bootstraps environment and creator contexts
- Scheduler launches per-creator streaming runtimes
- Platform workers manage platform-specific ingestion and publishing logic
- Shared browser and job systems are centrally controlled
- Clean shutdown propagates through all active tasks
- Twitch and YouTube chat workers connect to their respective platforms,
normalize incoming messages, and pass normalized events into the
TriggerRegistryfor evaluation. - Workers log emitted trigger actions for observability. They do not execute actions, dispatch jobs, or persist cooldowns.
- Business logic is intentionally deferred; workers remain limited to transport ownership, normalization, and trigger evaluation.
core/app.pyremains the streaming runtime authority for event loops, scheduler control, and shutdown.- The scheduler may start the Discord runtime but does so in isolation so it can be independently restarted without interrupting streaming workers.
- Discord control-plane behavior belongs under
services/discord/and its runtime scaffolding; no Discord logic should live insidecore/app.py. - Dashboard integration is planned (GitHub Pages first, Wix Studio later) and will share interfaces with the Discord control-plane for parity.
- Owns lifecycle of platform workers per creator, based on platform flags in
shared/config/creators.json. - Starts chat workers; does not evaluate triggers and does not execute trigger actions.
- Coordinates shutdown and resource cleanup across runtimes.
- Discord: ACTIVE — control-plane only, separate runtime, not part of the chat-trigger pipeline.
- YouTube: SCAFFOLDED — polling-based chat worker is trigger-ready; API calls and livestream discovery are deferred pending credentials/quota.
- Twitch: FOUNDATION — IRC-based chat worker implemented, architecture is complete and trigger-ready; temporarily untestable due to external account issues.
- Twitter/X: PLANNED — control-plane tasks exist; runtime worker scaffold is not yet implemented.
- Rumble: PAUSED — browser/DOM-based approach retained and documented; execution is paused due to upstream API protection. Architecture remains intact for reactivation.
- Transport: polling via
liveChatMessages.list(no push/webhook support) - Poll cadence: honor
pollingIntervalMillis; default scaffold assumes ~2–3s while API hints are wired - Rate limits:
liveChatMessages.listcosts 5 units/request; current quota is 200,000 units/day with ~50,000 reserved for overhead/other tasks, so keep intervals above 2s to avoid churn - Latency: expect a few seconds between message send and API availability; downstream triggers must tolerate slight delays and deduplicate by message ID
- Lifecycle: scheduler-owned workers will resolve
liveChatIdand poll chat; implementation is deferred until the scaffold is validated - Normalization: chat messages are normalized into platform-agnostic events,
evaluated by the
TriggerRegistry, and any emitted trigger actions are logged only (execution deferred)
Environment:
YOUTUBE_API_KEY_DANIEL— Data API key used for livestream discovery and chat polling
All Rumble chat workers, models, and browser helpers remain in the repository. Execution is paused solely due to upstream API protection and DDoS mitigation. The architecture and code paths are intentionally preserved to allow rapid re-enablement once official API access or platform whitelisting is available.
StreamSuites/
├── .env.example
├── .gitignore
├── LICENSE
├── README.md
├── RUNTIME_AUDIT_REPORT.md
├── changelog/
│ ├── README.md # Canonical runtime changelog expectations (manual/CI copy to dashboard)
│ └── changelog.runtime.json # Authoritative runtime changelog JSON format (structure only)
├── core/
│ ├── README.md # Core runtime boundaries and status
│ ├── __init__.py # Package init
│ ├── app.py # Streaming runtime entrypoint & lifecycle
│ ├── config_loader.py # Dashboard-compatible config ingestion + validation
│ ├── context.py # Per-creator runtime context
│ ├── discord_app.py # Discord control-plane runtime entrypoint
│ ├── jobs.py # Job registry and dispatch
│ ├── ratelimits.py # Shared ratelimit helpers
│ ├── registry.py # Creator loading and validation
│ ├── scheduler.py # Task orchestration and shutdown control
│ ├── state_exporter.py # Runtime snapshot export (platform + creators)
│ ├── shutdown.py # Coordinated shutdown helpers
│ ├── signals.py # Signal handling
│ └── tallies/ # Tally schema-only runtime concept (no execution)
│ ├── README.md # Scope and future readiness for tallies
│ ├── __init__.py # Export surface for tally dataclasses
│ └── models.py # Tally, category, option dataclasses + serialization
├── data/
│ └── streamsuites.db # SQLite runtime store (auto-created)
├── docs/
│ └── POST_MORTEM.md # Rumble ingest investigation summary
├── exports/
│ └── public/ # Static snapshot root for public gallery exports
│
├── services/
│ ├── clips/
│ │ ├── __init__.py
│ │ ├── encoder.py # FFmpeg wiring + deterministic outputs
│ │ ├── exporter.py # Clip state snapshot publisher
│ │ ├── manager.py # Clip runtime facade (queue + worker + export)
│ │ ├── models.py # Clip identifiers, title formatting, states
│ │ ├── storage.py # SQLite-backed clip persistence
│ │ ├── uploader.py # Clip upload helper
│ │ └── worker.py # Background worker + concurrency guardrails
│ ├── discord/
│ │ ├── README.md # Discord control-plane runtime architecture
│ │ ├── announcements.py # Control-plane notifications
│ │ ├── client.py # DiscordClient connection + command surface
│ │ ├── commands/
│ │ │ ├── README.md # Command layering rules
│ │ │ ├── __init__.py
│ │ │ ├── admin.py # Admin handlers (pure logic)
│ │ │ ├── admin_commands.py
│ │ │ ├── creators.py # Creator-scoped handler scaffold
│ │ │ ├── public.py # Public handler scaffold
│ │ │ └── services.py # Service-level handler scaffold
│ │ ├── heartbeat.py # Heartbeat loop for liveness
│ │ ├── logging.py # Logging adapters
│ │ ├── permissions.py # Admin gating via Discord-native flags
│ │ ├── runtime/
│ │ │ ├── README.md # Discord lifecycle ownership & supervision
│ │ │ ├── __init__.py # Discord runtime scaffolding
│ │ │ ├── lifecycle.py # Lifecycle hooks for Discord control-plane
│ │ │ └── supervisor.py # Supervisor for control-plane runtime
│ │ ├── status.py # Shared-state status persistence
│ │ └── tasks/
│ │ ├── README.md # Control-plane task constraints
│ │ ├── pilled_live.py
│ │ ├── rumble_live.py
│ │ ├── twitch_live.py
│ │ ├── twitter_posting.py
│ │ └── youtube_live.py
│ ├── pilled/
│ │ └── api/
│ │ ├── chat.py
│ │ └── livestream.py
│ ├── rumble/
│ │ ├── api/
│ │ │ ├── channel_page.py
│ │ │ ├── chat.py
│ │ │ └── chat_post.py
│ │ ├── browser/
│ │ │ ├── __init__.py
│ │ │ └── browser_client.py # Persistent Playwright browser control
│ │ ├── chat/
│ │ │ ├── rest_client.py
│ │ │ ├── sse.py # SSE ingest client (optional; falls back to API poll)
│ │ │ └── tombi_stream.py # SSE ingest helper
│ │ ├── chat_client.py
│ │ ├── models/
│ │ │ ├── chat_event.py
│ │ │ ├── message.py
│ │ │ └── stream.py
│ │ └── workers/
│ │ ├── chat_worker.py # Chat read/write logic (SSE preferred; API poll fallback)
│ │ └── livestream_worker.py
│ ├── triggers/ # Platform-agnostic trigger registry
│ │ ├── __init__.py
│ │ ├── actions.py # Built-in trigger actions
│ │ ├── base.py # Trigger interface (matches + build_action)
│ │ ├── README.md # Trigger pipeline concepts and score event notes
│ │ └── registry.py # Creator-scoped trigger evaluation (emit actions)
│ ├── twitch/
│ │ ├── README.md
│ │ ├── api/
│ │ │ ├── chat.py
│ │ │ └── livestream.py
│ │ ├── models/
│ │ │ └── message.py
│ │ └── workers/
│ │ └── chat_worker.py
│ ├── twitter/
│ │ ├── api/
│ │ │ ├── auth.py
│ │ │ └── posting.py
│ │ └── workers/
│ │ └── posting_worker.py
│ └── youtube/
│ ├── README.md
│ ├── api/
│ │ ├── chat.py
│ │ └── livestream.py
│ ├── models/
│ │ ├── message.py
│ │ └── stream.py
│ └── workers/
│ ├── chat_worker.py
│ └── livestream_worker.py
│
├── shared/
│ ├── config/ # Static configuration (JSON)
│ │ ├── chat_behaviour.json
│ │ ├── clip_rules.json
│ │ ├── creators.json
│ │ ├── logging.json
│ │ ├── monetization.json
│ │ ├── posting_rules.json
│ │ ├── ratelimits.json
│ │ ├── services.json
│ │ ├── services.py
│ │ ├── system.json
│ │ ├── system.py
│ │ ├── tiers.json
│ │ └── triggers.json
│ ├── logging/ # Structured logging helpers and adapters
│ │ ├── levels.py
│ │ └── logger.py
│ ├── platforms/ # Platform-neutral state tracking
│ │ ├── __init__.py
│ │ └── state.py
│ ├── public_exports/ # Read-only builders for public gallery exports
│ │ ├── __init__.py
│ │ ├── clips.py
│ │ ├── polls.py
│ │ └── publisher.py
│ ├── ratelimiter/
│ │ └── governor.py
│ ├── runtime/
│ │ ├── __init__.py
│ │ ├── quotas.py
│ │ ├── quotas_snapshot.py
│ │ └── scoreboards_snapshot.py
│ ├── scoreboards/
│ │ ├── README.md
│ │ ├── placeholders.py
│ │ ├── registry.py
│ │ ├── schema.json
│ │ └── snapshot.py
│ ├── state/
│ │ ├── chat_logs/
│ │ │ └── .gitkeep
│ │ ├── creators/
│ │ │ └── daniel.json
│ │ ├── discord/
│ │ │ ├── README.md
│ │ │ └── runtime.json
│ │ ├── jobs.json
│ │ ├── quotas.json
│ │ ├── scoreboards/
│ │ │ └── .gitkeep
│ │ └── system.json
│ ├── storage/
│ │ ├── chat_events/ # Placeholder for chat event persistence
│ │ │ ├── __init__.py
│ │ │ ├── index.py
│ │ │ ├── reader.py
│ │ │ ├── schema.json
│ │ │ └── writer.py
│ │ ├── file_lock.py
│ │ ├── paths.py
│ │ ├── scoreboards/
│ │ │ ├── README.md
│ │ │ ├── exporter.py
│ │ │ └── importer.py
│ │ ├── state_publisher.py
│ │ └── state_store.py
│ └── utils/
│ ├── files.py
│ ├── hashing.py
│ ├── retry.py
│ └── time.py
├── schemas/
│ ├── creators.schema.json
│ ├── platforms.schema.json
│ ├── system.schema.json
│ └── triggers.schema.json
├── clips/
│ └── output/ # Deterministic clip outputs (clip_id).mp4
│
├── media/
│ ├── capture/
│ │ ├── rumble.py
│ │ ├── twitch.py
│ │ └── youtube.py
│ ├── jobs/
│ │ ├── base.py
│ │ ├── clip_job.py
│ │ └── upload_job.py
│ ├── processing/
│ │ ├── metadata.py
│ │ ├── transcode.py
│ │ └── trim.py
│ └── storage/
│ ├── buffer.py
│ ├── cleanup.py
│ └── clips.py
│
├── runtime/
│ ├── admin/ # Dashboard/internal operational snapshots
│ │ ├── chat_triggers.json
│ │ ├── creators.json
│ │ ├── integrations.json
│ │ ├── jobs.json
│ │ ├── permissions.json
│ │ └── rate_limits.json
│ ├── exports/ # Deterministic public-facing snapshot files
│ │ ├── README.md
│ │ ├── changelog.json
│ │ ├── changelog.runtime.json
│ │ ├── clips.json
│ │ ├── meta.json
│ │ ├── polls.json
│ │ ├── scoreboards.json
│ │ └── tallies.json
│ ├── signals/ # Dashboard-only normalized events
│ │ ├── chat_events.json
│ │ ├── poll_votes.json
│ │ ├── score_events.json
│ │ └── tally_events.json
│ └── version.py # Application/runtime version information
│
├── scripts/
│ ├── bootstrap.py
│ ├── publish_state.py
│ ├── update_version.py
│ └── validate_config.py
│
├── tests/
│ └── __init__.py
│
├── rumble_chat_poc.py # Rumble chat validation script
├── rumble_poc/ # Persistent browser profile for Rumble PoC
├── twitch_chat_poc.py # Twitch chat IRC smoke test
├── test_rumble_api.py # Rumble API probe
└── requirements.txt
-
Authoritative data sources Platform APIs are used where available; browser automation is used only when required.
-
Single responsibility per component Browsers do browser things. Workers do platform things. The scheduler controls lifecycle.
-
No hidden background state All long-running tasks are tracked and cancellable.
-
Windows-first compatibility Signal handling, shutdown, and event loops are designed to behave correctly on Windows.
-
Configuration over code Behavior is being progressively externalized into JSON-based config.
StreamSuites may optionally capture chat events while platform bots are active to support historical replay and downstream analysis. Any future logging will be append-only, non-blocking, and explicitly optional so that failures never affect live chat operations. Logged data is intended for external consumers such as the StreamSuites dashboard, browser extensions, or moderation tools.
Planned scaffolding includes:
- A storage placeholder at
shared/storage/chat_events/for future writers, readers, and indexing utilities - A runtime state root at
shared/state/chat_logs/(with a Rumble namespace atshared/state/chat_logs/rumble/) reserved for generated data and kept gitignored - A
services/rumble/models/chat_event.pyplaceholder for describing Rumble chat event shapes without impacting current integrations
No logging logic is implemented yet.
Twitch connectivity uses the native IRC-over-TLS transport to keep behavior deterministic and scheduler-friendly. Foundational pieces live under:
services/twitch/api/chat.py— Twitch IRC client (connect/read/send, PING/PONG)services/twitch/workers/chat_worker.py— worker lifecycle wrapper for scheduler ownership (no side effects on import); normalizes chat events and routes them into the platform-agnosticTriggerRegistry, logging emitted trigger actions without executing them.services/twitch/models/message.py— normalized chat message + trigger-ready event shape
Twitch tokens live in .env:
TWITCH_OAUTH_TOKEN_DANIEL(required for IRC chat)TWITCH_BOT_NICK_DANIEL(chat nickname; defaults to channel name if omitted)TWITCH_CHANNEL_DANIEL(channel to join without the#prefix)TWITCH_CLIENT_ID_DANIEL/TWITCH_CLIENT_SECRET_DANIEL(documented for future Helix usage; not required for IRC chat)
A minimal Twitch chat validation script lives at the repo root:
python twitch_chat_poc.py --channel <channel> --nick <bot-nick>
# or rely on env vars: TWITCH_OAUTH_TOKEN_DANIEL, TWITCH_CHANNEL_DANIEL, TWITCH_BOT_NICK_DANIELThe script connects to irc.chat.twitch.tv:6697, prints incoming messages, and
responds to !ping with pong. Scheduler integration will attach the same
worker/client lifecycle when Twitch is enabled for a creator. Discord and other
runtimes remain unchanged.
- Quota enforcement (per-creator/platform, daily, buffer + hard cap)
- Quota snapshot export (runtime cadence →
shared/state/quotas.json) - Discord control-plane runtime scaffolding + dashboard state publish
- Twitch and YouTube chat trigger scaffolds (evaluation-only)
- Rumble chat workers (paused, preserved)
- Harden quota registry wiring across platform workers
- Expand dashboard quota surface for observability only
- Tighten shutdown ordering across runtimes
- Validate YouTube/Twitch trigger scaffolds with live credentials
- Chat runtime plumbing — Not yet live; dashboard chat/overlay views render preview/mock data only.
- Browser extension feed hydration — In planning / not started; extensions continue showing placeholder content until runtime feeds exist.
- OBS overlay runtime feeds — UI ready / runtime pending; overlay templates ship mock data only.
- Live chat socket ingestion — Planned; no active socket ingestion is wired yet.
- Multi-platform identity routing — Planned; identity mapping across platforms is not connected to runtime exports.
- Deterministic replay ingestion — Planned; chat replay overlays remain mock-data driven until ingestion wiring lands.
- Config-driven trigger definitions and cooldown persistence
- Dashboard tooling for creator config introspection (read-only first)
- Additional platform workers (Twitter/X control-plane parity)
- Scheduler telemetry + alert surfaces
- Trigger action execution + job dispatch
- Operator tooling (desktop control, runtime start/stop)
- Historical chat logging + replay (opt-in)
- Dashboard trigger editing and live controls
This repository intentionally prioritizes correctness and clarity over rapid feature accumulation. All new functionality is expected to respect the existing lifecycle and architectural boundaries.