Whim • Shipped 2026
iMessage group-chat agent
Role
iMessage Extension & Game Runtime
Timeline
Sep 2026 (Hack the North)
Team
Me
Chang
Jack
Karan
Skills
TypeScript
Cloudflare Workers
Durable Objects
Swift
iMessage Extensions
LLM Sandboxing
Overview
A friend in the group chat who makes the plan and the game
Whim joins an iMessage group chat through Linq's iMessage API. Ask it for dinner ideas and it posts a ballot the group votes on with tapbacks. Ask it to "make us a card game" and a playable game lands in the thread a few seconds later. Every chat gets its own stateful agent on a Cloudflare Durable Object, so Whim remembers the group's plans, votes, and scores.
Four of us built it at Hack the North 2026, where it won both the Best Use of Cloudflare and Best Use of Linq prize tracks. Chang, Jack, and Karan built the agent loop, research, and booking. I owned the games: the native Messages extension people play in, the engine that turns a prompt into a game, and the sandbox that runs model-written games.
The Messages Extension
Native game screens inside the thread
Whim's games arrive as iMessage app cards. Tapping one opens my Swift Messages extension, which renders the game natively: a lobby showing who's in, round and reveal screens that advance once everyone has answered, blackjack, and a finish screen with the result. Each phone syncs with the chat's agent over HTTP, so the whole group sees the same game.
The extension also ships Camera Runner, a dino-style runner you play by pinching your fingers at the front camera. Apple's Vision framework tracks the hand on-device and each pinch is a jump. A finished run can go back into the chat as a challenge poster for everyone else to beat.
When a game ends, Whim posts a result ticket into the thread with the winner and scores. Card images are pre-rendered into the chat's Durable Object as soon as they exist, which cut a card's load from a 2.2s cold render to under 0.1s.
The Game Runtime
From one sentence to a playable game
When someone asks for a game, a classifier model (Jev) reads the request and picks a surface: choice rounds (trivia, "who's most likely to", group verdicts) or tap-to-dodge. It also picks how the game scores: one right answer per round, points for matching the majority, or no points with the group's pick as the verdict. Below a 0.75 confidence floor, Whim goes with the likelier surface instead of asking the chat to choose.
A generator model then fills in a definition for that one surface. Zod validates it against the schema, the server trims it to the round cap and enforces the scoring rule the router chose, and a simulator plays it to completion before anyone sees it. The model writes data and the server runs the rules, so every game Whim posts is known to finish.
Sandboxing Generated Games
Running model-written HTML without trusting it
Card and dice games go to a third tier where the model writes the whole game as a single HTML page. The worker serves that page under a CSP sandbox without allow-same-origin, which gives it a null origin: the generated code can't reach the agent or widget APIs even though it's served from the same host. External scripts, images, and forms are all blocked, and the only endpoint that answers it is its own game state.
Multiplayer comes from a runtime I inject into every page. Game state lives in the chat's Durable Object as a revisioned blob and each write is a compare-and-swap on the revision, so when two phones tap at once, one gets a 409 and retries instead of overwriting the other. The runtime also draws a turn strip ("Your turn", "Waiting on Jeremy") from the game's fields, so every generated game shows whose move it is.
Learn More
Whim is open source: github.com/chang-07/htn-26