Inspiration
Every few months a streamer opens the wrong tab: an .env file, a password manager, an order confirmation with their home address, a login QR code. It's on screen for a second, but that's enough. It's in the VOD, the clips and someone's screenshot, and a leaked API key can turn into a four-figure bill within the hour. Blurring it afterwards doesn't help, because viewers already saw it.
We noticed most streamers already run a short stream delay. That gives a window: if something can read the screen before the delayed frame goes out, it can cover a secret before anyone sees it. That's Twitchy.
What it does
Twitchy sits between OBS and Twitch.
- Every 150 ms it screenshots the undelayed picture over obs-websocket and reads it with Apple Vision, on the streamer's Mac.
- 11 detectors look for API keys and tokens, passwords, emails, phone numbers, card numbers (issuer prefix + Luhn), public IPs, crypto seed phrases (BIP39 checksum), QR codes, fixed screen regions, a private watchlist (real name, address, family names, fuzzy-matched against OCR mistakes) and the streamer's own plain-English rules.
- A mask moves over exactly that spot in OBS. It's up long before the delayed frame airs, so viewers never see the secret.
- Twitchy, a pixel mascot, pops up on the overlay and announces the save in chat. The shield arms itself when you go live. Mods can type
!panicto black out the whole stream, and anyone can ask!twitchyhow many leaks it blocked. - A local dashboard handles one-click OBS setup, the watchlist and rules, live latency, a redacted leak log and an end-of-stream report.
No frame leaves the machine and there's no AI on the live path, so it costs nothing to run. The only AI call is turning a plain-English rule ("hide my student ID, it's the letter r followed by 7 digits") into a pattern, once. Twitchy then tests that pattern against its own examples and ordinary stream text before saving it.
How we built it
- Two developers, two tracks, two Codex threads: Track A (shield engine) and Track B (Twitch + Twitchy).
- A shared contract first: we agreed and committed a typed event contract before any feature code, so both Codex threads could build in parallel against mocks of the other side.
- AGENTS.md as Codex's rulebook: stay inside your track's folders, test your work, update the docs, commit small.
- Intent-based prompts: each feature went to Codex as a goal, context, constraints and a definition of done. Big features went in steps (for the Leak Gauntlet: scoring logic, then the page and runner, then a live run against OBS).
- The stack:
- TypeScript on Node 22, run with tsx
- a small Swift helper for Apple Vision OCR, kept running and fed frames over stdin
- obs-websocket for capture and masks
- Twitch EventSub over WebSocket and the Helix chat API
- a plain HTML/CSS/JS overlay and dashboard
- OpenAI structured outputs for the rules compiler
- CI: typecheck and tests on every push, plus an OCR accuracy test on a macOS runner.
Proof: the Leak Gauntlet
We didn't want to just say it works, so we built a test that tries to break it. npm run gauntlet flashes 37 fake secrets, 14 lookalikes and 3 quick flashes on a real OBS stream, and checks whether each mask was up before the frame aired.
On seed 3 (the demo run): 37/37 blocked, 0 false alarms, 3/3 flashes, p95 311 ms from screen to mask, against a 1000 ms delay. The lookalikes are the hard part: [email protected], password: string, an order number that fails Luhn, 8.8.8.8, and 12 wordlist words that fail the BIP39 checksum all stay visible.
Challenges
- The timing budget. One OBS Render Delay filter caps at 500 ms, so setup stacks them. Every step from capture through OCR, detection and mask placement has to fit inside the delay, with margin.
- Small text. Downscaling 1080p frames for speed made OCR miss most secrets in a 12 px editor font, so we read full resolution and keep one OCR process warm.
- False positives. A shield that masks everything is useless, so most detector work went into what not to mask: type annotations, versions, redacted placeholders, private IPs, order numbers.
- The Gauntlet caught a real leak. Before its page first painted, the browser source was transparent, and Twitchy read a real password from an editor behind it. The runner now draws an opaque backdrop first.
- AI rules you can trust. The rule compiler validates every model answer: regex safety, too-broad patterns, the description must not contain the secret, and the rule must catch its own examples and leave the lookalikes alone. It retries once, telling the model exactly what failed.
What we learned
The stream delay is the whole guarantee, and measuring beats claiming. Splitting the work into two tracks behind one contract is what let two Codex threads build at full speed without stepping on each other.
What's next
A Windows OCR backend (most streamers are on Windows), and multi-line matching for addresses that wrap.
Built With
- apple-vision
- css
- github-actions
- html
- javascript
- macos
- node.js
- obs-studio
- obs-websocket
- openai-api
- openai-codex
- swift
- twitch
- twitch-chat
- twitch-eventsub
- typescript
- websockets