Stage 5: pack config
Some knobs belong to the broadcaster, not the viewer: how long effects last, how many bots one redeem may spawn, how chat messages are branded. Pack config is the direction-reversed mirror of pack state — the broadcaster edits a value in the Dashboard, and the bridge delivers it to the adapter.
Declare the sections
Section titled “Declare the sections”Config is declared as titled sections of fields. Each field is an inline
JSON Schema, same shape as an event’s params_schema:
[[pack.config.section]]key = "effects"title = "Effects"subtitle = "How hard viewers can grief"[[pack.config.section.field]]key = "max_bots"type = "integer"minimum = 1maximum = 8default = 4
[[pack.config.section]]key = "chat"title = "Chat"[[pack.config.section.field]]key = "chat_prefix"type = "string"maxLength = 16default = "[chat]"Sections are presentation (Dashboard panels with headings); field keys live in one flat namespace across all sections. Values are schema-validated before they ever reach the adapter.
Receive config frames
Section titled “Receive config frames”Delivery is latched: right after hello_ack the bridge replays one
config frame per key with a known value, and pushes a fresh frame
whenever the broadcaster edits one. The adapter keeps a dict of defaults
(matching the schema defaults) and overwrites on every frame:
_config = { "max_bots": 4, "chat_prefix": "[chat]",}
# in the main frame loop:elif msg["type"] == "config": key, value = msg.get("key"), msg.get("value") if key in _config: _config[key] = valueApply frames idempotently — a replay after reconnect delivers values you may already have.
Use the values
Section titled “Use the values”Each config key lands in one handler:
-
max_bots— a broadcaster-side cap that clamps whatever the viewer asked for:count = min(int(params["count"]), _config["max_bots"]) -
chat_prefix— branding on every viewer message (run it through the same sanitizer as the message itself — it’s still text headed for a console command):prefix = sanitize_chat(_config["chat_prefix"])if prefix:message = f"{prefix} {message}"
Note the division of labor across the three broadcaster-facing surfaces:
- Event
params_schema— viewer-facing limits (count≤ 4), rejected before a redeem is paid for. - Per-reward params — values that are part of a reward’s identity, like
the timed events’
seconds(set in the Cue→Event mapping; two rewards, two durations, two prices). - Pack config — Pack-wide policy that applies across all rewards,
like
max_botsandchat_prefix. That’s the test: if you’d ever want two rewards to differ on it, it’s a param; if it should hold everywhere, it’s config.
Next: put the state on stream.
See also
Section titled “See also”- Pack Config schema — the reference page.