Circuit is ten daily puzzle games on one site with one record across them: Cipher, Abacus, Atlas, Doublets, Fathom, Hardwood, Hivemind, Keystone, Meridian and Outlier. The people who play dailies every morning play them on a dozen unrelated sites, with a separate streak on each and no way to tell whether they are getting better. Circuit starts from the bet that the games are the inventory and the layer across them is the product. Anyone can play from the first tap; signing in with Google keeps the streak beyond the browser.

The success bar was set before any code: about twenty friends and I play most mornings and keep our streaks. Strangers who stay, and eventually pay, would be better, but the design doesn't depend on them. What it does depend on is the operating side: a puzzle supply that never misses a morning, content that agents drafted and reviewers checked, and a cost of zero.

Circuit's Today page in dark mode: a floating header with Today, Games and Profile, a Next up panel for Abacus with a gold Play button, a side panel reading 1/10 done today with a seven-day streak and a countdown to new puzzles, and the start of the games list with Abacus up next, Atlas solved in two guesses and Cipher in progress
Fig. 1 Today on day 15. The lead panel is the next unplayed game, the side panel holds the one figure that matters this morning, and the list below holds all ten games.Screenshot of a local instance at 1440×810, 3 November 2026, against a throwaway database, never production. One anonymous player's history and today's plays are seeded: this is a demo, not real usage.

A puzzle plays only after someone approves it

Nothing is drawn on request. Each puzzle is generated ahead of time and stored, and it moves through three states: a draft until a reviewer approves it on the admin page, approved until its day arrives, and live from then on. A Cron Trigger runs at 05:01 UTC, one minute after the day turns, promotes everything approved up to today, and drafts the next 14 days for any game that has none. A second run at 05:31 promotes again, so a failed first run is covered.

Draft
the cron keeps 14 days of drafts per game, generated and stored before anyone needs them
Review
an allowlisted reviewer approves each day at /admin/puzzles; the page is a 404 for everyone else
Approved
playable from the moment its day begins, whether or not the cron has run yet
Live
the cron records the promotion; approving a day that has already arrived promotes it at once
Unavailable
a day nobody approved shows as a state on the home page, never an error
Fig. 2 One puzzle from draft to the morning it plays.Drawn from src/lib/play/generation.ts, custom-worker.ts and the README's puzzle-supply section.

The order of those rules is the point. An approved puzzle is playable from the start of its day, and the cron's promotion records that rather than causing it, so a late or missed cron run costs nobody a puzzle. The build refuses to ship a bad answer list: it fails if a word is on the blocklist, if an answer is over its par budget, or if a bundled word module is out of date.

Cipher on day 15: a five-wide grid with CRANE and STOIC played, A, E and T marked, a third row of ZZZZZ with a red 'Not in word list' above the grid, a Hint button with 3 left, and a large 4 left with six pips, two spent
Fig. 3 Cipher with four guesses left. ZZZZZ is refused with a reason and costs nothing; the count of guesses left sits beside the title rather than in a small label.Screenshot of a local instance at 1440×810, 3 November 2026, against a throwaway database. The puzzles are seeded; the three guesses were played through the app.

One standing, honest at small numbers

Games give scores that cannot be compared: guesses used, a factor off, points. The obvious common currency, your percentile against today's players, breaks at twenty players. It moves in steps of 1 in 20 and swings on who happened to show up. So every puzzle ships with a par, computed by a reference solver and capped, which works with one player.

Then I played every game, and par read worse on screen than it did on paper. It left the interface. It still sets each puzzle's difficulty and the rotation, but the solved screen now shows the result as one large figure, your last 30 days of that game, your streak, and how you compare with everyone else today. That comparison appears only once 10 players have finished the puzzle. Before that, nothing is shown in its place.

There is only one streak, site-wide, and finishing any one daily keeps it going. Miss a day and the streak survives if you finish that day's puzzle from the archive within 48 hours, twice in any 30 days. A repaired day is marked as repaired.

Atlas's solved screen: a large 2/6 with two of six pips lit, an answer card for Hungary reading Europe, 9.5M, 93k km² and Landlocked, a gold Cipher button beside Share, tiles for time 1:38, streak 7 and today 1/10, and a Last 30 days strip with bars for the last two weeks
Fig. 4 The solved screen every game shares, here Atlas in two. Next game is the one gold button. The strip has two weeks of bars because the site is 15 days old, and there is no comparison with other players because a local demo has fewer than 10.Screenshot of a local instance at 1440×810, 3 November 2026, against a throwaway database, cropped below the header. The history is seeded rows and the solve time was set to 1:38.

Content drafted by agents, gated by blind review

Ten games a day for months is a lot of content. Agents drafted the questions, a pipeline checked them, and reviewers who hadn't seen the answers sampled them against bars set before the results came in. Two of those gates failed first.

Keystone shows clue words and asks for the word that links them. The plan was to score guesses by GloVe word-vector similarity. Measured on the drafted rounds, GloVe accepted 29.7% of bridge rounds against a gate of 40%, and ConceptNet Numberbatch managed 32.9%. So bridge rounds moved to drafted boards of graded answers, and only the closest-word rounds kept GloVe. The bank that shipped holds 806 rounds. Its first final review failed: recall 0.82 and within-one 0.87, against bars of 0.90. Once the boards were widened, a second review passed at 0.96 and 0.94.

Fathom is napkin math, three questions a day, scored by how many orders of magnitude off you are, averaged. It began as recall of national statistics and was rebuilt around questions worth working out. Of 737 drafted, 116 shipped after research, blind estimates, checking every source against the opened page, and a screen for napkin math. The bar was 80% of a 40-question sample enjoyed, and the last sample missed it by one, at 31 of 40. Every question a reviewer didn't enjoy was cut. I shipped the 116 knowing that.

GateBarFirst resultShipped on
Keystone word vectors (bridge rounds)40% accepted29.7%drafted boards instead
Keystone final review, recall / within-one0.90 / 0.900.82 / 0.870.96 / 0.94 after widening
Fathom, enjoyed in a sample of 40322431; shipped by decision

Free tiers as the design brief

Circuit runs on Cloudflare Workers Free and Neon Free, so its limits shaped the code. A request gets 10 ms of CPU, and the gzipped Worker stays under 2,050 KiB. Fathom's and Keystone's question text lives in Postgres, reached through Hyperdrive; only indexes, par tables and the attribute games' fact tables are bundled, so the runtime never runs a solver. The cap applies to cron runs too: six games' first draws in one run measured about 9 ms, so generation is split between the 05:01 and 05:31 runs, each game in exactly one. The games list and today's live set are remembered per isolate for 60 seconds.

The deploy script exists because of a trap in the adapter. OpenNext copies every .env file it finds into the bundle as fallback values, so a plain deploy could ship a laptop's secrets as production's defaults. The script blanks them before upload, so a missing secret fails closed. The same rule runs through the rest: the admin allowlist means nobody when it's unset, and the cron route returns an error and does nothing without its token.

The games keep changing after launch without breaking anyone's day. Hardwood's card now has six clues, from height and rookie year to latest team and conference, and a play begun on the old card finishes on it. Hivemind and Outlier now play one stage at a time. The new cell colours are tested for contrast and for colour-blind players.

What isn't done yet is written down too. I have no usage numbers worth citing, and Fathom's 116-question bank is due a top-up before its first repeats come round.

At a glance
Games
10 · daily, unlimited, archive
Supply
drafted 14 days ahead
Goes live
only once approved
Streak
one, across every game
Keystone bank
806 rounds, blind-reviewed
Runs on
Workers Free + Neon Free