UCLA ran a tournament for AI agents: each entrant drafts a Pokémon team against an opponent, then battles it, turn by turn, on a 50-second clock. My agent went 0–4 on its first day. Eight days, eight deploys and 83,000 simulated games later, this is how it plays a turn.
Every match starts with a shared pool of Pokémon. The two agents draft six each, 15 seconds a pick. Each then secretly brings four and chooses two to lead, and the battle runs as Pokémon doubles: both sides choose a move for each of their two Pokémon at the same time, every turn, with 50 seconds to decide and a seven-minute bank for the whole game. Each match starts with fresh memory; nothing carries over from one opponent to the next.
Other entrants used everything from a plain language model to a search engine that simulates turns ahead. The scoring is Swiss rounds, then a best-of-three bracket.
A language model is a poor damage calculator and a good judge of a well-presented position. So the work is split. Code drafts (15 seconds is too short for anything else), builds a damage sheet for every turn, and lists the strongest candidate plays. Claude Opus reads the sheet and picks one, and the code can still overrule a pick that scores far below the best option.
Scores every card in the pool against the cards the opponent can still take. A pick takes well under a second.
Simulates the opening turns of each lineup against their likely leads for 20 seconds, then Opus makes the final call.
Wednesday night, two days before the tournament. Testing match, turn 1. I watched this game live, and this turn decided it. Scroll through it the way the agent saw it. Every number below is from the agent's own decision log.
Our sun team leads Incineroar and Torkoal. Torkoal's Drought sets sun on entry, and sun boosts Fire moves by half. Their leads are two fast Water attackers. Scroll to step through the turn.
Eruption is marked guaranteed to knock Iron Bundle out. Hold that thought.
A reasonable read of the sheet it was given. The model agreed with the code, and the sheet was wrong.
The sheet priced Eruption at Torkoal's HP before the turn. Two faster opponents meant it would almost never fire at full strength.
Eruption's knockout chance drops from guaranteed to 33%.
each square ≈ 10 games · green: only the fix won · black: only the old build won
The fix won 54 games the old build lost, and lost 42 it won. Found Wednesday night, tested overnight, shipped Thursday morning as the submitted version.
Both of their Pokémon move before Torkoal. Iron Bundle is more than eight times faster.
The code works out every hit, both ways. Sun-boosted Eruption looks devastating: 161–191% of Iron Bundle's HP.
It ranks complete plays for both of our Pokémon. The top one takes the "guaranteed" knockout and aims Knock Off at Basculegion.
Opus reads the sheet and the ranked plays and agrees with play #1. The code would have overruled a much weaker pick. It had no reason to here.
They read the Knock Off and switch. Iron Bundle hits first. Eruption goes off at a quarter of its power, and the game tilts from there.
Eruption gets weaker as its user loses HP, and the sheet never asked whether Torkoal would still have its HP when it moved.
Now Eruption is credited with the HP Torkoal will probably have when it moves. Replayed, the top play becomes Heat Wave, which knocks Iron Bundle out at any HP.
A fix ships only if it holds up in matched simulator games. Each square is one pair of games on the same draft.
A single live game proves nothing, and a win rate over a few hundred games hides small effects in noise. So every change was tested in paired games: the old build and the new one play the exact same drafts, seeds and opponents, and only the games where they disagree count.
Two practice opponents did the playing: a clone of the search bot from day one, and a switch-heavy practice bot I built after losing three games to an agent that kept switching out of my attacks. Below are the real results for the Eruption fix.
Not a big effect, and that is the point: most changes are small. The bar for shipping was no harm in both, with a reason grounded in a real game. Ideas that failed the bar did not ship, however good they sounded.
The first version lost all four games to a search bot. Reading the transcripts, the losses had one shape: my agent valued every move as if the opponent would stand still. It aimed a "guaranteed knockout" at a Pokémon that simply used Protect. It attacked into a switch. It never priced in the hit it would take after moving.
Squares are live testing matches against other entrants (filled = win). Green tags are deploys, each one tested in paired simulator games before it went live.
Live record after the rebuild: 6–4 in testing matches, 0–3 of it against one switch-heavy agent. In simulation the submitted build wins 49% against the search-bot clone and 55% against the switch-heavy practice bot.
Tournament: Friday, October 16, from 10 am PT. Result to come.
I ran this as the lead, with Claude Code doing the engineering. Each piece of work (a fix, the practice bot, the docs) went to a background agent in its own copy of the code, and a single progress log kept every decision, test result and deploy. The simulator decided what shipped. A few rules never bent: no other entrant named anywhere in the code, nothing public until the deadline, and nothing changed on tournament day.
Halfway through the week the agent moved from my laptop to a Mac mini. The last two deploys went out over SSH to a machine with no monitor attached.