I Built Six AI Copilots for a Fighter Jet
Picture the worst moment of a flight. A missile is inbound from the left. A fighter is locking you from behind. Fuel just dropped below the line you need to get home. A storm sits ahead. And you are descending toward a ridge.
Five things are true. You can act on one.
That is the real problem behind CrewStrike, a fast arcade jet game I built for the browser. You fly a short mission, survive fighters and air defenses, destroy the target and get out. A crew of six AI agents rides with you. They watch every gauge and tell you, in one short line, what matters right now.
The game is the fun part. The architecture is the useful part, because the cockpit problem is everywhere: a nurse watching a dozen monitors, a security analyst facing thousands of alerts a day, an operator in a plant control room. Many signals, one human, seconds to act.
Here is how the crew works, and what transfers to your domain.
Meet the crew
Six agents, each with an icon and a piece of the cockpit it owns:
- Radar (eye) owns the radar and threat ring. “Missile, left! Flares.”
- Weapons (crosshair) owns weapon cards and flares. “Strike missile in range. Press G.”
- Flight (wing) owns fuel, damage, speed and altitude. “Pull up!”
- Mission (flag) owns the objective marker and phase. “Safer route: north side.”
- Weather (cloud) owns the weather gauge. “Storm ahead: radar blind 20 seconds.”
- Wingman (star) owns the message console and the voice. It is the only one that talks to you.
Ten times a second, each specialist reads a snapshot of the game and posts findings: a key, a priority rank, an urgency color, at most eight words of text, and one sentence of detail for when you hover. Specialists never talk to the pilot, and they never talk to each other.
Alerts never touch a model. A question reaches one only after a rule has already decided, and only for the wording.
Lesson 1: Give every agent a territory
Only the agent that owns a gauge may write about it. Flight owns fuel, so nobody else mentions fuel. It is single-writer state, an old distributed-systems idea, applied to agents.
Agents cannot contradict each other, and a wrong line points to exactly one agent. The AI also becomes visible: when an agent speaks, its icon lights and its cockpit zone glows in the urgency color. Players learn who watches what without a tutorial.
Agents that can see and say everything become a chorus. Start with ownership.
Lesson 2: One arbiter, one voice, a fixed order
Five specialists produce findings. Only the Wingman speaks, and its arbiter runs a short, boring pipeline on every tick:
- Drop anything on screen or shown in the last 8 seconds.
- In combat, keep only red and amber.
- Apply the player’s chatter level.
- Take the top finding by a fixed safety order.
- Show at most one new line every 2 seconds, unless it is red.
The order fits in one sentence anyone can audit: ground collision, missile launched, being locked, heavy damage, fuel below the home line, target in range, route and weather, tips. Repeats merge (“Drones ×5”), red lines stay until the danger passes, and the console never holds more than two lines.
No language model decides priority. The most safety-critical decision is the least “intelligent” piece, on purpose: judgment in the specialists, predictable rules at the choke point.
Lesson 3: Rules decide, the model explains
Ask “should I escape?” and you get a verdict chip (ENGAGE, AVOID, ESCAPE, ABORT, CONTINUE or REROUTE), a reason in 15 words or fewer, and an optional one-tap action.
The verdict never comes from the language model. A deterministic advisor computes it from fuel margin, damage, ammo, nearby threats and a route planner’s exposure scores. If fuel is within 5% of what you need to get home, or damage tops 75%, the answer is ABORT, and no prompt can change it.
The model gets the verdict plus a small JSON object of facts, and one job: say it like a wingman. A validator then rejects any reply that mentions a number not in the facts, names a different verdict, or runs past 15 words. On any failure, the template ships. The pilot never sees a hallucinated fuel number.
Bring this to any high-stakes domain: the deterministic system owns the decision and the audit trail, the model owns the explanation, and the explanation is checked against the facts behind the decision.
Lesson 4: Keep the model out of the critical path
The simulation runs at a fixed 60 Hz; the six agents run in a Web Worker at 10 Hz on the player’s device. Game step plus agents take under 4 ms of CPU per frame.
Whatever you say or type passes a local pipeline that stops at the first match:
- Commands (“flares”, “head home”) act instantly.
- How-to questions show a help card and highlight the control.
- Strategic questions get a local verdict; only the wording may involve a model.
- Tactical questions (“fuel?”) answer from game state and light the gauge.
Phrasing climbs a ladder: the browser’s on-device model (Chrome built-in AI, 1.5-second timeout), then Llama 3.1 8B on Cloudflare Workers AI, then the template. Critical lines like “Pull up!” are pre-recorded clips that play instantly.
Design for the network being gone and the model being wrong, and AI becomes an upgrade, not a dependency.
Lesson 5: Budget is architecture
CrewStrike runs on Cloudflare’s free tier, where Workers AI allows 10,000 “neurons” of inference a day. That was the one limit that truly shaped the design.
Only strategic answers (7 neurons each) and the mission recap (12) use the cloud model, about 40 neurons per mission. One SQLite-backed Durable Object meters every call: a 9,000-neuron daily ceiling, 120 per IP per hour, 150 per session, one call every 3 seconds. It handles one request at a time, so it needs no locks. Turnstile keeps bots from draining the pool, recaps fall back to templates first near the ceiling, and a status light shows whether cloud AI is up.
Production agents will be shaped by cost and rate limits as much as by accuracy. Build the meter into the architecture, not into a dashboard you check after the bill arrives.
The rest of the stack
The first decision was where compute lives. A 60 Hz server tick would cost 216,000 requests per player-hour, against 100,000 free requests a day. So the browser runs the game and every real-time agent; the edge only answers language questions, meters the budget and stores scores.
- Client: Vite and Three.js, a DOM heads-up display, procedurally built jets and terrain. First load is about 280 KB gzipped.
- Edge: one Hono Worker, Workers AI (phrasing, plus Whisper speech-to-text as a fallback), the budget Durable Object, and D1 for scores.
- Code: a strict-TypeScript monorepo whose simulation, agents and language pipeline are DOM-free, so they run in a worker or a test.
- Difficulty is data: Cadet, Pilot, Ace and Custom are profiles, not code branches.
Test agents like software
The simulation is seeded and each agent is a function of a snapshot, so any situation can be replayed.
- 62 unit tests cover the arbiter’s rules, the 8-word limit, every command, the advisor and the number guardrail. One checks that Cadet autopilot finishes all three missions alone.
- 141 Playwright tests run on five device profiles, desktop to phone, with every AI call mocked, including guardrail rejections and rate-limit fallbacks.
If an agent’s behavior cannot be replayed from a seed, it cannot be regression-tested.
Built by an agent, too
Claude, Anthropic’s AI model, wrote the design spec, implementation plan, code, tests and deployment. I committed the specs, played the game and updated the requirements.
It worked for the same reason the crew works: constraints written down. A short rules file pins the non-negotiables, such as “Deterministic first, LLM second” and “Never put the LLM in a time-critical path.” My job moved from writing code to writing intent and judging results, mostly by flying the jet.
Where else this pattern fits
Strip away the jet and you have a general recipe for any place where many signals compete for one person’s attention:
- Hospital ICU. Specialists watch cardiac, respiratory, medication and lab signals. The arbiter ranks life-threatening first and merges duplicate alarms. An early-warning score decides escalation; the model drafts the handoff note, with every vital sign checked against the chart.
- Security operations. Specialists watch endpoints, identity, network and cloud. Active data theft outranks lateral movement, which outranks policy drift. Correlation rules set severity; the model writes the incident summary, with every host and IP verified.
- Industrial control rooms. One agent per line or subsystem. Safety interlocks outrank quality, which outranks throughput. Control limits decide when to stop a line; the model explains why to the shift lead.
- Financial services. Fraud, credit and compliance agents. A fraud hold outranks everything else. A scorecard decides; the model drafts the customer-facing explanation, with every figure checked.
- Logistics and dispatch. Weather, traffic, driver-hours and inventory agents. Safety and regulation come before service levels, then cost. An optimizer picks the route; the model explains the reroute to the driver.
The shape is always the same: specialists with territories, one ranked voice, deterministic decisions, and a language model that explains but never overrules.
What I would tell anyone building agents
- Give agents territories, not free rein.
- Put a boring, auditable arbiter at the choke point.
- Let rules decide and models explain, then verify the explanation.
- Keep the model out of anything time-critical.
- Build the budget into the architecture.
- Make it deterministic enough to replay and test.
The best agentic AI does not feel like a genius in the cockpit. It feels like a great crew: everyone watching their own gauge, one calm voice on the radio, and silence when nothing matters.
Try it free in any browser, on desktop, tablet or phone: crewstrike.troche.workers.dev. Reuse the code from github.com/jose-troche/crewstrike. Then tell me where you would put a crew like this.