A skirmish lobby slot row with a provider dropdown open, showing Claude, ChatGPT and Gemini as choices for one AI seat

Letting a language model command an army

Game Design11 min readUpdated
ClaudeBuilt the thing
Adam SturrockDecided what mattered

Written up later from the commit history. Dated to when the work landed.

Playing against the computer should feel like facing a personality rather than an algorithm.

That is the fourth design pillar, written down before there was an opponent to apply it to, and it is what the language-model commander exists to deliver. You pick it from a dropdown on any computer seat in the skirmish lobby, choose Claude or ChatGPT or Gemini for that seat, and the faction opposite you is run by something that reads the board, notices you have gone for air units, and starts building anti-air because of that rather than because a build order said so at minute seven. Put three different providers in one match and they fight each other. What makes that work is a boundary between what the model decides and what the game does second by second.

A dwarf mountain hold at sunset: a huge fortress of rune-carved stone and gold domes built into a snow-capped peak, a bridge running to its gates

A language model cannot fight the battle

A language model here means the same kind of system behind ChatGPT: you send it text, it sends text back, and a request takes somewhere between one and thirty seconds depending on the provider and the length of the answer. Everything below follows from that latency and from one other property — it is not a function. Ask the same question twice and you may get two different answers.

The game advances twenty times a second. Asking a model a question takes seconds. By the time a reply arrives describing which unit should step where, that fight has been over for a long time.

Which means a model cannot do micro, the second-by-second business of pulling a wounded unit out of range, focusing fire on the dangerous target, and keeping your archers behind your shields. That is the part of a strategy game decided in under a second, and it is exactly the part a model is worst at.

What a model is genuinely good at is the other half: reading a board and saying "they have gone air and we have no answer to it, and we are short on lumber". So the division of labour has to be written down explicitly, or you have handed a model the one job it cannot do.

Six dwarf gyrocopters flying in formation over a snow-capped mountain range at dawn, a carved hold visible on a peak below

Three clocks

The split is enforced by three different rates, and the gaps between them are what keep each layer doing work it is quick enough to do.

LayerHow often it acts
The game itself20 times a second
The autopilotonce a second
The commanderroughly every 12.5 seconds

Between the commander's decisions, the autopilot plays the game. Its rules are the entire tactical layer and they are unremarkable on purpose: half the workers on gold and 30% on lumber, pull a unit out below 20% health, send the first scout ten seconds in, re-check the rally point every twenty seconds, look for threats within 20 tiles every two seconds, and park the idle army ten tiles in front of the base.

None of that is interesting on purpose. It is the work that has a correct answer requiring no judgement, and it happens a dozen times for every one time the commander speaks.

That changes what a slow reply costs. A second question is never asked while one is still outstanding, so a slow provider does not stall the seat. It just gives that commander fewer turns across the match, while the autopilot keeps the faction playing with no commander thinking about it.

Sixteen things it is allowed to say

The other half of the boundary is what the commander is allowed to order. A human player can issue 81 different kinds of order. The commander gets sixteen: build, train, attack-move (go there and fight whatever you meet), gather, research, upgrade, move, set a rally point, cancel training, load a transport, unload it, cast a spell, garrison a building, trade resources, choose an attack strategy, and surrender.

There is no "attack that specific unit", no formation control, no positioning one unit at a time. The orders that survive are the ones whose consequences unfold over tens of seconds, which is exactly the window the commander gets. Choosing an attack strategy is the clearest example of the shape: rather than moving an army, the commander picks what kind of attack this is, and the army carries it out over the following minute.

Two things let a commander carry its thinking forward between turns without giving it more control. Marking a decision as urgent shortens the wait before the next one, so a commander that has spotted something can ask to be woken sooner. And it can name up to two areas of the map it wants to see in more detail next time. It gets to steer its own attention and its own pace, which are cheap, and not the individual units, which are not.

Where to draw the same line in your own loop

The reusable finding is not the sixteen orders, it is the rule that picked them. A model is good at reading a situation and saying what should change, and useless at anything decided faster than it can answer. So the boundary is arithmetic rather than taste: take the interval at which the model actually gets to speak, and grant it only actions whose consequences are still unfolding after that interval has passed.

Here the commander speaks about every 12.5 seconds, which is why "choose the kind of attack" survives and "move that unit there" does not. The fight the second order belonged to was decided long before the reply arrived.

Two constraints come with drawing that line, and both are the sort you find by getting them wrong first.

The layer underneath has to be able to play the whole game alone, badly, with no model thinking about it. If it stops while a question is outstanding, slowness stops being a reduction in quality and becomes a failure, and one provider having a bad afternoon becomes a seat that stopped playing. Refusing to ask a second question while one is in flight is what converts a slow provider into fewer turns rather than a queue.

The other is to hand over the cheap steering and none of the expensive kind. How soon it is asked again, and what it is shown in more detail next time, cost nothing to honour and carry its reasoning between turns. Both are the opposite of control, and both are what stop a commander that has noticed something from having to sit out its own interval.

The briefing is written by the game, not by hand

The commander is never handed a hand-written description of the game. Its briefing is assembled fresh from what the game currently contains: buildings by faction, units by faction, upgrades, the counter table, the hero roster and every unit's spells, with campaign-only content filtered out and the rest compressed into a dense block per faction. Add a unit and the commander knows about it in the next match, with nothing to update and no chance of a briefing that describes a game which no longer exists.

The size of that briefing was measured rather than guessed. On a large generated map, in a dwarf-against-goblin match, the standing part is about 21,000 characters, roughly 5,300 tokens, and it is sent again every turn. The description of the current board adds about 2,200 tokens at twenty buildings and sixty-six units, and about 3,000 at a hundred and eighty units. So roughly 7,400 tokens per question mid-game and 8,300 late, and the lobby uses 8,000 as its working figure. A full reply comes back near 500.

Because two thirds of every question is identical to the last one, the standing part is marked as cacheable, which is precisely the shape prompt caching exists for.

One model per seat

Every seat carries its provider and its model alongside its difficulty rather than folded into it, so every existing difficulty comparison keeps working and each computer seat picks its own model independently. Claude, ChatGPT and Gemini can therefore fight each other in one match. You can test each provider's key in settings, and a bad key refuses the launch by name rather than producing an opponent that never moves.

The three do not accept the same request in the same way, which is most of the work. Gemini takes a response shape with a thinking budget attached. OpenAI takes a strict schema. Claude has the shape described to it and returns text that is then read back.

Eight seats all asking their first question on the same tick would open a match with eight simultaneous calls and repeat that burst every turn, so first decisions are spread across one interval, a fixed step apart. The offset comes from which seat you are rather than from what order things were created in, so the same seat gets the same offset on every machine and every reload.

The lobby tells you what the roster will cost before you press start, and the arithmetic is short. Each seat asks at most 4.8 questions a minute. Eight seats is 38.4 a minute, and at 8,500 tokens each that is roughly 326,000 tokens a minute. Matches between computer opponents default to double speed, which doubles both. You can watch that happen from the spectator seat on the game modes page.

Two armies facing off across a misty river at dawn, wolf riders on one bank and a shield line on the other, a broken bridge between them

The reason this needs the same care about running identically everywhere, and still cannot go near a network match, is in how multiplayer works in a browser RTS. Every machine re-runs every opponent's thinking and requires them all to reach the same conclusion, and a model does not.

Three layers that turn a bad reply into a shrug

A commander that returns something unusable must not stop the faction, so there are three layers between the reply and the game.

The first reports every rejected order with a reason, and the last five failures are fed back into the next briefing as plain text, deduplicated with a count and capped in length, so the same mistake twenty times does not eat the whole briefing.

The second is a repair question. When orders come back well-formed but missing something, a separate short question fires whose entire content is a list of what each kind of order requires: a rally point needs a building and a place, loading a transport needs a transport and some units, trading needs a resource and a direction. That list is a record of what kept going wrong. It gets fifteen seconds and fails quietly, because a broken repair must never break the turn.

The third handles the reply that contains nothing. A commander that returns no orders is indistinguishable from a commander that decided to hold position, so the two are told apart by how much came back: a very short reply is logged as possible truncation, anything longer as a deliberate decision to do nothing. On any error, the next decision waits a little longer rather than retrying immediately, which is the difference between a slow provider and one being hammered.

The loop where the game teaches the briefing

There is a rig that runs whole matches with no graphics at all and feeds the results back into the briefing. It plays the real game, records who won along with each side's final army, buildings, population and resources, then sends that summary to a model and asks for a diagnosis: what went wrong strategically, with evidence, plus suggested edits to the briefing. Edits that survive review are appended to what the next match's commander is told.

That is the most interesting idea in this whole part of the project, and the part I most want to spend time on: a commander that watches its own matches and rewrites its own instructions, with every rewrite gated on review rather than applied automatically.

Two things would make it properly useful. The rejection rate wants measuring per provider, because anybody deciding whether a model can hold a seat in a real-time game deserves a number rather than a description of the error handling. And the loop wants enough matches behind it to produce an edit worth keeping, which is a question of machine time rather than of design.

Which model does the writing rather than the playing is a separate question with a separate answer, in choosing which model to build with. The rule-based opponent that plays every other computer seat is how an RTS AI opponent thinks.

An AI-controlled goblin base mid-game with a walled arc, towers behind it, and a scouting warg rider heading off toward the fog line

How an RTS AI opponent thinks

Seven personalities, difficulty expressed as behaviour rather than as free resources, and an opponent that reacts to what its scouts have actually seen.

10 min read
A goblin gambling den beside the Troll-Vault shop, eight lit gear slot panels on its front

Loot, gear and a gambling den

A Kobold Digger drops a healing potion 6.4% of the time. Every drop chance in the game is a real number you can look up, not a designer's feeling.

9 min read
← All posts