Inspiration
Every stream chat already makes predictions: "he's dead", "ez win", "she'll never make it under a minute". They scroll away and nobody remembers who was right. Twitch Predictions exist, but only for Affiliates and Partners, they run on Channel Points, and the streamer has to set up the outcomes in advance. Most streamers can't use them at all. We wanted every channel, from day one, to turn chat's guesses into something that is tracked, settled fairly and remembered, in the viewers' own words.
What it does
Called It is a small bot the streamer runs on their own machine, plus an OBS browser overlay and a local streamer panel. It is not a Twitch Extension, so there is nothing to install or review.
!call <anything>: one short call per viewer per round, in plain words ("win under 45s", "Kai never drops below half HP").- The game runs the rounds. When a boss spawns, the game tells Called It and a round opens on the overlay and in chat; calls lock 20 seconds later. When the boss dies (or the player goes down), the result is set with the fight time.
- Auto-grading without AI. Calls like
win,lose,win under 45sare graded from the game's own numbers. Anything else stays with the streamer, who marks it right or wrong in one click. - A jury of chatters. When the streamer sends a call to a jury, Called It draws jurors from people who chatted recently but did not call in that round; they vote
!agree/!disagree, and the overlay shows the verdict. - Records that carry across streams.
!recordshows a viewer's settled calls and streak,!topthe leaderboard, and viewers who come back on a later stream get a welcome-back toast with their record. - Privacy first.
!forgetdeletes everything Called It stores about a viewer. It stores Twitch user IDs, display names and the text of!callclaims, never raw chat messages, in a local SQLite file. Chat only goes to Twitch (for the bot's replies), never to analytics or AI services, and there are no LLM calls at runtime. - Works for any channel. Chat commands only: no channel points, no Bits, no Affiliate status. Manual rounds (
!round,!lock,!result) work for any game or any moment, not only games that send events. - Game API: a game posts three events (
boss_spawn,boss_dead,player_down) to a localhost endpoint with a per-run token.npm run game-simsimulates a game, so you can try it without mine.
How we built it (how Codex was used)
All of Called It's code and tests were written in one main Codex thread (session 01a17051-673d-71c1-a540-c7bd788b698e), on the ChatGPT Free plan, so every prompt had to be small and precise.
- Spec first. I wrote
SPEC.mdandAGENTS.md(product rules, test command, privacy constraints, "no new dependencies") before the first prompt. - Step by step. Codex built the domain core (rounds, calls, jury, records, commands) as pure, tested code; then persistence, Twitch device-flow login, EventSub chat and a paced chat sender; then the local server, overlay and streamer panel; then demo tooling and the README; then the game endpoint.
- Rehearse live, hand Codex what broke. From the first Twitch login on, each step ended with a real run on my Twitch channel. Bugs found there went back into the same thread with the log, and came back as a fix plus a test: Twitch's device flow reporting
authorization_pendingin themessagefield, an EventSub reconnect storm (HTTP 429), stale rounds blocking a new session, a locked round left empty by!forget, jury card placeholders. Reviewing the demo video found two more (a failed chat send could stop the app; the welcome-back fired inside the same stream), and the video shows that real Codex run, sped up. - Numbers: 12 prompts in the main thread, 9 commits of Codex-written code, 60 tests passing, 0 LLM calls at runtime.
The game itself (Haunted Survivors) is my own game; its small Called It hook is a separate GDScript file that just posts the three events, and is included in the repo as an example.
Challenges
- Twitch's device flow puts
authorization_pendingin themessagefield, which the first version missed; EventSub reconnects can trigger 429s if each reconnect opens a new subscription. - Grading fairly without AI: we limited auto-grading to exact patterns the game can prove, and left the rest to people (streamer or jury) instead of guessing.
- Demoing a chat feature without an audience: the demo uses 3 test accounts on my own channel, disclosed in the video and README.
Accomplishments
- A full loop that runs on a real Twitch channel: game event, chat calls, auto-grade, streamer settle, jury, records across streams,
!forget. - No paid APIs and nothing to install on the viewers' side.
What we learned
Small, well-specified prompts plus a live rehearsal after each step made Codex far more reliable than one big request: each bug arrived with a reproduction, and each fix came back with a test.
Known limits / what's next
- Calls lock 20 s after the boss spawns, so in a very short fight (the 17 s Pumpkin King in the video) calls are still open while the fight is on screen. Next: the game sends a "boss incoming" event, the round opens then and locks at spawn.
- The demo was recorded before the welcome-back fix, so the video still shows welcome-back toasts inside the first stream.
- An SDK snippet for Unity/Godot/Unreal, season leaderboards, and a hosted version so streamers don't have to run Node locally.
Demo disclosure
The viewers in the video are 3 test accounts (calledit_bot1-3) driven by a script, and the streamer's panel clicks are scripted. The Twitch chat, the bot replies and the game events are real, on twitch.tv/tsang326. The video shows the game, the Called It overlay and the real Twitch chat side by side in one page, recorded locally rather than captured from a live broadcast.
Built With
- godot
- node.js
- openai-codex
- sqlite
- twitch
- typescript
- websockets
Log in or sign up for Devpost to join the conversation.