Building 'Is It Christmas' in 2026

484 AI agents. 16 million tokens. Turns out today is not Christmas.


isitchristmas.com has done one thing for fifteen years: tell you whether it’s Christmas. Eric Mill (@konklone) built it. The genius behind it is that it’s always doubled as an excuse to try new web tech. Look at the source or the git history. There’s a websocket in there, live multiplayer cursors, a phone-app manifest, an IFTTT hook.

Claude Code added a feature I intellectually understood but don’t have a great mental model for: dynamic workflows. The idea is simple - Claude writes code that spins up a swarm of subagents. Lots of them. But when does it make sense to reach for this tool? Always? Anything that feels complicated (to me)? When I know the task is massively parallelizable? So I did the konklone thing and pointed it at a problem that needs exactly none of it.

The end result looks identical to the original: “NO” (at least for today). However the implementation and the journey is nothing short of absurd, and taught me some lessons along the way.

Dynamic Workflows in Action

To make the problem sufficiently interesting, rather than just check the local user’s timestamp, I decided to implement 121 voting algorithms that would decide in parallel if it was indeed Christmas or not. Seems like a great task for a swarm of subagents to build in parallel (vs a massive 1-shot Claude Code loop).

At the top is one Claude Code instance I’ll call the Coordinator. It’s the one I talk to. The Coordinator wrote the test suite, wrote out 121 algorithm assignments, wrote the scripts that run the swarm, launched them, read the results back, and decided what to do next.

To make this very clear, the Coordinator doesn’t write 121 algorithms itself. It writes a script that calls 121 other Claudes, each to write their own. The script (new in Opus 4.8) is plain JavaScript with no model inside it, and the runtime runs it in the background. It gets a couple of special functions, and the one that matters is agent():

// agent() boots a fresh Claude with its own context, shell, and tools,
// points it at one task, and hands back a structured result.
const result = await agent("write an algorithm that...", { schema: RESULT });

agent(prompt) spins up a complete Claude, gives it one job, and waits. Pass a schema and you get a clean object back instead of a wall of text. parallel() runs a list of those at once, sixteen at a time, up to a thousand:

// 121 agents, one per algorithm, all running at once
const algorithms = await parallel(
  specs.map((spec) => () => agent(writePrompt(spec), { schema: RESULT }))
);

A .map() wrapped in parallel(). That’s the swarm: throwaway Claudes that each do one job and vanish, with their answers landing back in the script as plain objects. (There’s a sibling, pipeline(), for stages instead of a batch.)

So the chain is: I point the Coordinator at the problem, the Coordinator writes a script, the script hires the swarm, and the answers flow back up the same path. That last step, the answers flowing back up, is the half the headlines skip, and it’s where the real question lives.

121 Claudes

To get a feel for fan-out, let’s consider the 121 completely different algorithms that each Claude wrote: a simple date-time match, a hash table that memorized every Christmas through 2400, a hand-weighted neural network, a Brainfuck interpreter, the date in Roman numerals, the date in Morse code, the date in base 60 like the Babylonians (obviously).

Asking 121 agents to write 121 date algorithms is 121 chances to be subtly wrong, and I wasn’t going to read 121 hand-rolled calendar algorithms to find the broken ones. So before the swarm, Claude wrote a test suite: a Node script that runs each algorithm against 148,488 known dates, covering every timezone, leap years, and the hours on either side of midnight where date bugs hide. Big and brute-force, nothing clever.

The parallel() snippet above doesn’t show this because it isn’t in the orchestration code. It’s in what each agent was told in its prompt: “write your algorithm, run it against the test suite, fix what fails, and don’t report back until it’s green.” Each subagent has its own shell, so it runs the tests and loops on its own. The script just launches the 121 and collects what they return.

115 passed on the first try. My favorite used Rata Die, an old trick for counting days as one running number, and got a single constant off by one: 719163 instead of 719162. That one digit pushed about 20,000 of the test dates a day early, specifically around midnight in the far-eastern timezones. The test suite caught it. When all 121 reported done, the Coordinator ran the suite once more over the whole set, to be sure nothing slipped through on a self-report. Neat.

Wave two: who watches the watchers?

In Wave Two, the Coordinator wanted to verify and code review it all: “Does this code do what it claims” and “where would it break”. So the Coordinator fanned out a second swarm, 363 Claudes this time - three per algorithm:

await parallel(algorithms.map((algo) => async () => {
  const [honest, fragile, oneLiner] = await parallel([
    () => agent(`Does this code do what it claims?\n${algo.src}`, { schema: VERDICT }),
    () => agent(`Where would this break?\n${algo.src}`,           { schema: VERDICT }),
    () => agent(`Describe it in one sharp line.\n${algo.src}`,    { schema: LINE }),
  ]);
  return { id: algo.id, honest, fragile, oneLiner };
}));

The outer parallel() fans across all 121 algorithms; the inner one asks three questions about each at once. The lines after that parallel() are ordinary code: tally the verdicts, keep the disagreements, drop the rest.

Ooh! Fun fact: this swarm found a subtle bug that the test suite missed: the hash table version only works up until year 2200, which the test suite didn’t test for.

A few of the voters, in the words of the agents that wrote them:

(The rest are in the appendix if that’s your idea of a good time.)

I get it now!

All the local Node code never ships. It’s all just code that Claude wrote and runs locally to organize the subagents deterministically. The word deterministically is doing a lot of work in that sentence (OMG did I just use a Claudism in my own writing? Snake, eat tail.). And that’s the new difference between Dynamic Workflows and the previous “cross your fingers and spin up a subagent if your task description roughly matches the subagent’s purpose” that I was hoping to grok with this exercise.

In conclusion

   
Agents 484
Tokens used 16,000,000+
What ships to your browser 121 algorithms and a vote counter
Learning to use Dynamic Workflows priceless (technically $85)

Is It Christmas remains the best site on the Internet. My Claude Code “internal” workflow scripts are in the repo if you want the real thing instead of the simplified snippets here. Open the console on my version to watch 121 algorithms agree on the obvious.

Appendix: the whole parliament

All 121 voters, grouped by cohort, each described by the agent that wrote it. Every one is also in the page source.

Calendrical Classics (12)

Epoch Arithmetic (13)

Recursion & Functional (10)

Lookup & Memoization (9)

Number-Base Maximalists (13)

Stringly Typed (11)

Intl & Locale (10)

Esolang & Exotic Interpreters (10)

Machine Learning Cosplay (13)

Physics & Astronomy Cosplay (8)

Cursed & Over-Engineered (12)


I'm Ben Stein, co-founder and CEO of SuperDuper, helping underwater parents manage all their family logistics. I live in Oakland with my Keeper wife Arin, our two overprogrammed teenage boys, and a dog named Soup who contributes nothing helpful to the family logistics and arguably makes them harder, but he's really cute.

If you want to follow along: superduperlabs.com · benjaminste.in · LinkedIn · Substack