Tuesday morning my role was eliminated. That evening I opened a fresh session on a brand-new model and asked it for something fun. By 9 PM there was a three-stage, 16-bit beat ‘em up where the hiring process is the final boss and an AI is your player 2. By 6:37 the next morning it was live on the internet.

The game is OPEN TO WORK. You play me. Your co-op partner is TOKEN, a small robot sidekick that hits hard and is sometimes confidently wrong. Together you fight through the Job Board, survive the Take-Home Tunnel and take down The Panel. It runs in a browser, on a phone or a desktop. The repo is public: every commit, test and journal entry behind this story is in it.

The model was Claude Opus 5.5, running in Claude Code. This is a field report on what it was like to ship a real, small product with it: where it earned its keep, where it slipped, and the few places where I was still the part of the system that mattered.


🧪 The Setup

One session, one instruction file, no benchmark

The session opened at 18:05 on Tuesday, September 22, on my home workstation. It was my first session on Opus 5.5. I asked for something fun that would show both what I can do and what this model can do. Claude came back with a co-op beat ‘em up in which the job hunt is the enemy and an AI is player 2. My reply is in the log verbatim: “JFC I love it.”

The pitch pulled from things I have built before. One game worked because of one tight mechanic. Another landed because it was local, true and affectionate. My retro loves include TMNT, Battletoads and Earthworm Jim, and the belt scroller is also the most scope-safe genre if you have four days. Claude weighed and rejected a fighting game (it lives or dies on balance) and an atmosphere-first explorer (wrong register). Both decisions are in the journal.

The harness matters more than the model name, so here it is.

  • Claude Code with Opus 5.5, and its 1M-token context window, as the coding agent.
  • My global instruction file. It is a few hundred lines of rules that load into every session. The ones that shaped this build:
    • Verify before you hand anything over.
    • Never install packages without asking.
    • Code, tests and docs ship in the same commit.
    • Sweep every generated file for stray non-ASCII characters.
    • Keep an append-only journal as you go.
  • Phaser 3, TypeScript strict, Vite and Vitest for the game.
  • The Codex image pipeline from my projects wiki for the sprites (more on it below). Claude first proposed a video-based route; I pointed it at the pipeline I already trusted.
  • A local qwen3.8-27b on the same machine for TOKEN’s dialogue.
  • Cloudflare Workers for hosting.

The art: one pipeline made the biggest difference

Across the games I have built recently, the biggest jump in quality came from how the character art is made. My Claude Code skill character-still now packages that knowledge: it produces a game-ready character image and knows three ways to get one, in order of preference:

  1. A local ComfyUI stack: free and offline, matted onto flat magenta for chroma keying.
  2. The Codex CLI’s built-in image tool, running on my ChatGPT subscription. It returns genuine transparent cutouts, so there is no matte step at all.
  3. The OpenAI Images API, metered, as the fallback for a machine with neither.

This build took the second route directly, through the Codex scripts in my projects wiki rather than the skill itself. Each sheet was one codex exec call asking for Genesis-style frames in a single row on a transparent background, and took about a minute. The first probe sheet held the character’s face, beard and hoodie across all four frames on the first try. Approved character designs then became the reference images for every later animation sheet, and a Python step snapped each sheet to its own 15-colour palette, the way Genesis hardware did it. That is why the sprites look like a 1993 cartridge rather than a 2026 image model.

This is not a benchmark. There is one build, one repo and one instruction file. I did not run the same task on another model, and I did not track tokens, cost or latency while it ran (a rough after-the-fact cost is at the end). Every time in this piece is wall-clock local time, read from commit timestamps or the session log.

🎮 The Game in Sixty Seconds

Three stages, eight enemy kinds, one very honest robot

The OPEN TO WORK title screen: a pixel-art Matt in a red t-shirt and TOKEN, a small white robot, on a city street under the logo, with a START, CV, CONTACT menu along the bottom.
  • Stage 1, the Job Board. A classic belt brawl. You fight ATS BOTs that shred your resume and Spam Recruiters that throw business cards along their depth line. The boss is The Unpaid Take Home, which calls in “scope creep” (one more ATS BOT) at two-thirds and one-third health.
  • Stage 2, the Take-Home Tunnel. A hover-board run through a server room. TOKEN calls out the hazards, and on its “Go wild” order one call in four is confidently wrong.
  • Stage 3, the Interview Tower. LeetCode Golems that shrug off jabs, Ghosters that vanish and reappear behind you, and The Panel: three interviewers at their desks, beaten one at a time.

TOKEN takes three orders. “Go wild” hits the biggest crowd. “Focus” doubles damage on whatever you last hit. “Guard” stays at your side and takes hits meant for you. TOKEN has 144 lines of dialogue across 18 moments, and the ending card links to my real CV.

Leave the title screen alone and it behaves like an arcade cabinet. After ten seconds it introduces the enemies one at a time under a NOW HIRING banner, then the bot plays a silent 30-second demo of the street with a blinking PRESS START, then it loops. That was my idea from the first playtest. Claude’s addition was to make the demo a test subject: the exact demo runs headless in the test suite, and Matt has to survive it. It also kept the demo silent, reasoning that an attract mode that blares from a phone left on a table is hostile.

The cast, and the line each one arrives with. The Ghoster’s is my favorite.

"The real one is open to work."

MATT, pixel-art sprite
MATT

"Hallucinated that one."

TOKEN, pixel-art sprite
TOKEN

"Filters you out by keyword."

ATS BOT, pixel-art sprite
ATS BOT

"Has an exciting opportunity."

SPAM RECRUITER, pixel-art sprite
SPAM RECRUITER

"Should only take two hours."

THE UNPAID TAKE HOME, pixel-art sprite
THE UNPAID TAKE HOME

"Invert this binary tree."

LEETCODE GOLEM, pixel-art sprite
LEETCODE GOLEM

"Will circle back."

GHOSTER, pixel-art sprite
GHOSTER

"Just a quick chat."

THE SCREENER, pixel-art sprite
THE SCREENER

"Walk me through your code."

THE TECH LEAD, pixel-art sprite
THE TECH LEAD

"Let's talk numbers."

THE HIRING MANAGER, pixel-art sprite
THE HIRING MANAGER
Stage 1: Matt and TOKEN fight an ATS BOT on the street, with a Final Fight style name card reading 'ATS BOT: Filters you out by keyword.'
38 commits in 14 hours 7 minutes, from the first design doc at 18:36 on Tuesday to the last fix at 08:43 on Wednesday. About 6,700 lines of TypeScript, 3,000 lines of tests, and 325 tests by the last commit (284 in Vitest, 41 for the Python asset pipeline), with the suite green at every commit from the first line of code on.

🌙 Ninety Minutes Unattended

M4 and M5 were scheduled for Thursday. Both shipped Tuesday night.

The design doc planned eight milestones, M0 to M7, over four days, Tuesday to Friday, under a working title that was also the pitch: “Laid off Tuesday, shipped by Friday.” M1 landed at 19:07, while I was still answering questions. At 19:18 I gave one standing instruction: “Go forward. Make reasonable assumptions. Only pause when you believe my input is required.” Then I mostly left it alone.

Here is what that bought:

  • 19:07 (before the instruction): M1 playable. Matt walks, punches and flattens ATS BOTs.
  • 19:26 to 19:58: touch controls (my question from 19:12), TOKEN as an AI partner, Stage 1 difficulty, and the rest of the Stage 1 cast.
  • 20:14: Stage 2, the tunnel.
  • 20:37: Stage 3, The Panel, and the ending. The full campaign now runs start to finish.
  • 20:53: M5. A synthesised soundtrack (four tracks, 18 sound effects) and TOKEN’s bark bank, generated by the local model.

Two milestones scheduled for Thursday were done before 9 PM on Tuesday. The Friday milestone, the public deploy, landed at 06:37 on Wednesday.

graph LR
  subgraph TUE["Tuesday evening"]
    direction TB
    A["18:36
design doc"] --> B["19:07
M1 playable"] B --> C["19:18
'go forward'"] C --> D["19:26 to 20:53
M2 to M5, unattended"] end subgraph WED["Wednesday morning"] direction TB E["05:10
I play it,
send a list"] --> F["05:37 to 06:27
seven playtest fixes"] F --> G["06:37
live on Cloudflare"] G --> H["07:47 to 08:43
link card, CV menu,
a regression"] end TUE -- overnight --> WED style TUE fill:#0A0A0F,stroke:#8888A0,color:#E8E8EC style WED fill:#0A0A0F,stroke:#8888A0,color:#E8E8EC style A fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style B fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style C fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style D fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style E fill:#0A0A0F,stroke:#8888A0,color:#8888A0 style F fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style G fill:#1A1A2E,stroke:#E94560,color:#E8E8EC style H fill:#1A1A2E,stroke:#E94560,color:#E8E8EC

The speed is not the interesting part. What matters is how it behaved while nobody was watching.

Claude Opus 5.5 logged assumptions instead of asking. The milestone entries in its journal end with a list of assumptions, two of them headed “Assumptions made without Matt (overrule freely)”, with seven for Stage 3 alone. That is the right shape for an unattended run. I could skim what it had decided and overrule any of it, and it never stopped to ask a question it could answer itself.

It worked in parallel. Sprite generation takes a minute or more per sheet, so it ran the art as a chain in a background terminal session and kept writing code while the images rendered. The chain logged every signal it received, because background jobs on this machine have been killed before and I wanted to know why.

It played the game. The workstation is headless, with no display attached, so Claude played through headless Chromium and read the screenshots. The first time it did that, on M1, it found a real input bug: 12 jab taps scored nothing. The input system sampled held keys once per 16 ms simulation tick, so a fast tap that went down and up inside one tick simply vanished. Claude’s inference: a human on a high-refresh screen would have lost presses the same way. After the fix, the same script scored 548 and dropped a bot.

It handed TOKEN’s dialogue to a local model. Claude wrote a small generator that gives qwen3.8-27b, running on the same workstation, a persona for TOKEN, house rules (never name a real company or person, no profanity, wry but never bitter, plain ASCII, short enough for the speech bubble) and three hand-written seed lines for each of 18 moments, from the “Go wild” order to “you got hired”. It asks for 14 candidates per moment, filters them (length, plain ASCII, no hashtags, a banned-word list) and fills the moment to eight lines, seeds first. The game never calls a model; the bank is generated once and committed. Curation is data too: weak lines go on a veto list, and a rerun refills the slots from the saved spare candidates without calling the model again. 14 generated lines were vetoed in review and replaced from the spares, leaving 90 generated lines beside 54 seeds. Qwen’s favourite joke turned out to be the 404 error: three of those went (plus a 401), and three survive. Some that stayed: “I’m your firewall now.” “Read. No reply. Repeat.” “This is a benefit, not a bribe.”

It tuned difficulty with bots, not vibes. Each stage has a scripted bot that plays it: a SHARP bot that plays well and a CASUAL one that plays like a first-timer. Claude ran sweeps over ten random seeds and set the difficulty from the win rates. Stage 3’s first cut was brutal. The CASUAL bot playing solo won 0 of 10 runs, and with TOKEN it won 6. Claude retuned the Golem and The Panel’s cooldowns and added a coffee pickup in the lobby, and got CASUAL solo to 3/10, CASUAL with TOKEN to 9/10, and SHARP to 9/10 solo and 10/10 with TOKEN. That last gap was a design goal: the AI sidekick should visibly matter. The bands are pinned in tests (over five seeds, to keep the suite fast), so a later balance change cannot quietly break them.

It found bugs no unit test could see, all by driving the real game:

  • A deep link booted the wrong stage.
  • “Play again” restarted the last stage instead of the first, because Phaser hands a restarted scene its old start data.
  • The street froze on its second visit, because of stale sprite maps. This one predated Stage 3.

🔍 Claude Refused to Trust a 200

Most of the value was in the checking.

If I had to name one behaviour that made this build shippable, it is this: Claude did not believe its own work until something outside its head confirmed it. Here is what that looked like in practice.

Measure, then assert, then break it on purpose

For the end-to-end test (a bot playing the whole campaign, street to tower, across ten seeds), Claude first ran the campaign, then wrote the thresholds from the numbers it saw. Then it mutation-tested its own suite by deliberately breaking the code and checking that the tests failed.

That caught a vacuous assertion. A check called “the tower still bites” was passing even when no run reached the tower at all. It was green for the wrong reason. Its build journal has the line I would put on a poster, an old TDD rule never put better:

"A test you have not seen fail is not yet a test."
- Claudefucius

Body, not status

The ending card was supposed to link to my CV at immatt.com/cv/. When Claude checked, the URL returned 200 OK, but my site has a catch-all that serves the home page for unknown paths. A status check would have shipped a “CV” button that opened my home page. Claude compared the response body to the home page, found them byte-identical, and fell back to the contact page until the real CV page existed. When it later went live, Claude rechecked by body again before flipping the link.

Deploys verified by content

When the game went live, “it returned 200” did not count as verification. Claude checked:

  • The md5 of the served index.html against the local build - an excellent validation approach, and one that a human is unlikely to ever do.
  • The bundle’s size and content type.
  • A made-up path, to confirm a real 404 (so later checks can’t be fooled by a catch-all).
  • The alias domain’s 301, over both http and https.
  • A full headless browser run: the title, a street fight and the tunnel, with no console errors and no failed requests.

When I asked for a link preview card, it fetched the page and the image with the user agents of five crawlers: Slack, Facebook, X, Discord and LinkedIn. Its reasoning was that bot protection silently blocking unfurlers is the likely failure, and a normal curl would never see it.

Looking beat reading

Several of the best catches came from Claude looking at its own output rather than reasoning about the code:

  • Its first favicon was TOKEN’s side-view head. It looked at it at tab size, judged it unreadable, and switched to the one front-facing view of TOKEN in the game before shipping.
  • The title logo was drawn off screen. The code looked right. The screenshot did not. (Phaser’s BitmapText.width already includes the scale, so the logo was being scaled twice in the centring maths.)
  • I reported The Panel strobing. Claude had guessed one cause, getup invulnerability, and a screenshot confirmed it. The second cause only surfaced because a probe screenshot was missing a character. Beaten panelists are marked dead but never removed, so they blinked forever as “fading corpses”.
Stage 2, the Take-Home Tunnel: Matt on a hover board in a server room, TOKEN riding behind him calling 'JUMP!' as a striped hurdle approaches.

It read the engine’s source before building on a claim

Two examples:

  • Before wiring the CV link, it checked how Phaser handles keyboard input and found that Phaser queues key events and processes them later. A window.open from a Phaser key handler therefore runs outside the browser’s user-gesture window, and popup blockers eat it. It opened links from plain window listeners instead. There is no Safari on the box, so its note on Safari’s popup blocker is marked “(inferred, Safari)” rather than claimed as tested.
  • Before adding an auto-pause on a hidden tab, it read Phaser’s source and found that Game.onHidden already stops the loop. Only window blur needed wiring.

It thought about the bill

The alias domain (otw.immatt.com redirecting to opentowork.immatt.com) had an obvious implementation: a redirect inside the game’s Worker. Claude noticed that the simple way to do that, run_worker_first: true, routes every request through a Worker invocation. A page load is about 65 requests, and the free tier allows 100,000 Worker requests a day, so that would cap the game at roughly 1,500 plays a day before requests start failing. (Scoping run_worker_first to a list of paths would have softened that; the journal does not show Claude weighing it.) It split the redirect into its own tiny Worker instead, so the game is pure static assets, which Cloudflare serves free and without a cap, and only alias visits run a script. That is platform cost sense, not just API knowledge.


💥 What It Got Wrong

The failures are the useful part.

Every item below is from the model’s own journal, written at the time. Some it caught itself. One I caught.

It made up timestamps

This is the headline behavioural finding. Claude kept an append-only journal with timestamped headings. It ran date plenty of times for other work, but the journal headings it typed from its own sense of the time. At 06:27 on Wednesday, writing an entry, it compared and found it had been stamping headings by guess. The stamps ran up to 47 minutes ahead of real time, and some were out of order. One entry said 07:00; its commit said 06:13.

The stamps were plausible-shaped. Nothing about them looked wrong. It corrected six headings to their commit times and switched to calling date for every stamp from then on. A few earlier future-stamps were never corrected and are still in the journals.

The lesson generalises: a long autonomous run drifts on facts the model never measures. Time is the obvious one. Anything the model “knows” without checking is a candidate.

A regression reached production, and I found it

At 08:15 on Wednesday, Claude shipped a START / CV / CONTACT menu on the title screen. Its verification covered keyboard, mouse, and phone taps on the menu options and on empty screen, in portrait and in landscape.

It never tested the touch stick, which is the one input a phone player uses to move a menu cursor.

Within half an hour I was on my phone, pushing right to reach CV, and the game started instead. The title’s “tap anywhere to start” listener was also hearing touches on the on-screen control pad.

The diagnosis was good. It went past my symptom and found two more cases from the same cause:

  • A pad button pressed with CV selected also started the game.
  • In landscape, the stick’s zone physically covers the START option.

The fix sorts every touch by what is under it. It is covered by tests and was verified live with emulated (CDP) touch drags in headless Chrome. But the test plan had a hole shaped exactly like the thing a real user would do first, and a human found it in minutes.

A silent failure in its own tool

The TOKEN bark generator asked the local qwen model for candidate lines. On the first run, qwen’s replies came back empty because its token budget was too tight. The generator treated each empty reply as “zero candidates” and wrote seeds-only categories without complaint. Claude caught this by reading the output, not from a test.

The fix did the right two things in one edit: it raised the budget, and it made the failure loud (a finish_reason check and a non-zero exit), so a starved run can never again pass as a quiet one.

Misdiagnosis, briefly

A composed screenshot sheet showed missing-texture boxes. Claude checked the running game’s texture list, found every sheet loaded, and then worked out that the screenshot file itself was stale from an earlier run. It checked the live system before changing any code, which is the right instinct. But checking file modification times would have answered the question in one step.

Writing from memory

Claude writes its journal fast, and sometimes from memory:

  • Two details in the Stage 3 journal (panelist props, the wording of a retune) had to be corrected against the asset manifest and the diff before commit.
  • On Wednesday, its first journal draft said a menu had been “5 pixels right of centre”. Rechecking the old code showed that 5 pixels was the width error. The offset was half that, 2 to 3 pixels. It caught this before the commit.

Self-inflicted tooling hits

  • The DNS negative cache. Before deploying, it ran dig to confirm the new hostnames were free. That left an NXDOMAIN in the local resolver’s negative cache, so every post-deploy probe from the box failed. It diagnosed this in one step (query 1.1.1.1 directly) and pinned resolution to verify. The check before a deploy broke the check after it.
  • pkill. A pkill -f pattern matched its own shell and killed the verification command.
  • The dev server. Restarting it killed the terminal session it lived in, because the server was that session’s only process.

An honest limit

Claude never heard the soundtrack. It verified the audio by instrument: a spy on the browser’s audio context counted voices, checked mute and reload behaviour, and fired every effect. The commit message and the roadmap both say the mix is unheard, instead of implying it is done. I would rather have that sentence than a confident one.

Stage 3, the Interview Tower: Matt faces a hulking grey LeetCode Golem in a sunset office, with a name card reading 'LEETCODE GOLEM: Invert this binary tree.'

🧰 Gotchas Worth Stealing

Eight traps from this build

GotchaWhat happensFix
codex exec -i is variadicThe prompt after -i is swallowed as another image pathPut -i <file> after the positional prompt
Phaser queues key eventswindow.open from a key handler runs outside the user gesture and gets blockedOpen links from a plain window listener
RetroFont.Parse typingTyped as returning the font data, it returns the whole cache entry; the failure is an opaque reading '84'Read the (short) parser source instead of guessing
Image models and textA painted “WE’RE HIRING” banner came out 42x14 px: unreadableDraw text in code with your own pixel font
run_worker_first: trueEvery asset request costs a Worker invocationPut redirects in their own script-only Worker
NXDOMAIN negative cacheChecking a name is free before deploy breaks your own check afterQuery a public resolver directly, or pin with curl --resolve
Catch-all 200sA missing page answers 200 with the home pageCompare response bodies, not status codes
Tools and formatters decoding \u escapesLiteral non-ASCII characters land in source filesSweep with grep -nP '[^\x00-\x7F]' after every write

The last one bit twice during the build. Prettier rewrote a \u00e9 escape in a test into a literal character, and the file-writing tool decoded \uXXXX escapes in Python source. Both were caught by a one-line grep that my instruction file runs after every generated file, for exactly this reason.


🤝 Where I Was Load-Bearing

It asked once. It should have.

Here is every place a human decision changed the outcome, in order:

  1. The pitch. Claude proposed it; I approved it.
  2. The calendar. It thought the day was Monday. It was Tuesday. Even the smartest models still struggle with time.
  3. The art route. It proposed generating video; I pointed it at a sprite pipeline I already trusted.
  4. The playtest. I played the build and sent back a long list at 05:10 on Wednesday: a special move that strobed, a Panel that flickered, three desks piled on top of each other, tunnel jumps that looked like clipping, and text too blurry to read. Claude cannot feel whether a game is fun. It can measure win rates and read screenshots, and it did both, but the list of what felt wrong came from a person holding a controller. Game development still requires a human in the loop - for now.
  5. The hostname and the deploy. In the Wednesday-morning stretch after the playtest fixes, Claude stopped exactly once: at the publish boundary, with the build and a dry-run deploy already green, asking both questions (which hostname, and whether to deploy) in a single prompt. I picked the name and said “deploy now”.
  6. “Not gated.” I asked for the CV and contact links on the title screen, so nobody has to beat the game to hire me.
  7. The touch stick. My phone found the regression its test plan missed.

The split was clean. I supplied taste, the playtest, and the go/no-go on anything public. It supplied everything that could be measured, and it measured more than I would have.

While I would like to claim that I made this game, that wouldn't be honest. This game was 99% Claude Opus 5.5. Aside from a broad concept, which I offered mostly to distract myself from the sting of being laid off, Claude was the creative genius and the masterful engineering executor. Of the Claude 5 family, Opus 5.5 has so far been my favorite to work with. It's a creative workhorse that defaults to iterative collaboration at the start of a session, but it will also run long tasks autonomously when nudged to, making sensible assumptions and solid course corrections along the way without much need for a human in the loop. This project has been a very fun one, and a much-needed distraction from... well, I think that's pretty obvious 🤣 I look forward to many more projects with Opus 5.5.
The HIRED ending: Matt holds up an offer letter on a rooftop at sunset while TOKEN cheers beside him. The card reads 'Built in 2 days by Matt Ezell + Claude' above a 'Hire the real Matt' menu with CV, CONTACT and PLAY AGAIN.

I'm not exactly sure why Claude made me quite this buff, but who am I to argue?


⚠️ What This Isn’t

One build is a story, not a statistic.

  • n = 1. One product, one repo, one instruction file, one person steering. A different project would surface different failures.
  • No controlled comparison. I did not run this build on Fable 5.1, Sonnet 5 or a local model. I had planned comparison tracks for this evaluation, and none of them ran, because the game ate the time. What I do have is experience: about a dozen games built with Claude models over the past couple of months. Earlier models were strong on the productive side and struggled with creative technical execution, the part where a game has to feel good, look coherent and actually be fun. On that record, Opus 5.5 is by far the most capable I have worked with. That is one builder’s judgment, not a measurement; measuring it is the next Deep Dive.
  • Rough cost, not a measured one. Afterwards, the session’s own logs gave the token counts for the build window, Tuesday 18:08 to Wednesday 08:45: about 1,070 Opus 5.5 calls, 1.0M output tokens, 3.1M tokens written to the prompt cache and 128M read back from it. At Anthropic’s published API rates that comes to roughly $70, in three near-equal parts: output, cache writes and cache reads. The 128M is the price of a long session: every turn re-reads the whole conversation, and caching is what keeps that affordable. I ran it on a subscription, so my marginal cost was zero; the sprites used ChatGPT plan quota and TOKEN’s lines ran on my own GPU. No latency figures. The “14 hours” is wall-clock between the first and last commit, and it includes a long overnight gap in which no commits landed.
  • The harness did a lot of the work. The behaviours I credit above (verify before handover, the non-ASCII sweep, the journal) are all spelled out in my instruction file. Pausing before the deploy was not: the file only said never to push or open a PR without confirmation, and Claude extended that to publishing on its own. The fair credit is model plus harness. A bare prompt would not get this discipline for free.

🔮 What’s Next

The measured version

  • The comparison runs. The same brief on other models, with token and cost tracking, turns this from a story into an evaluation. That is the next Deep Dive.
  • A leaderboard for the game. It is the next milestone on the roadmap.
  • You. Play it on your phone or your desktop, and send me what breaks, or read the source. TOKEN would like you to know that it is sometimes confidently wrong. So is its author.

Stay building. 🛠️

— Matt