A turn-based grand strategy game on a real-Earth hex map, where your opponent is a large language model you choose. Coding agents wrote the code and most of the documentation. I set the direction, wrote the prompts and coding rules, and reviewed the results.
Agent Wars is a WEGO game ("we go"), where neither player can see what the other is planning. For each turn, both sides create combat, movement, and production orders at the same time, based on partial, subjective views of the battlefield. Once players are ready, the game executes their orders and determines the outcomes (think: "Axis & Allies" meets "Diplomacy", with a software referee).
The game is intended to be simple to learn and quick to play, but with enough depth to make things interesting and believable.
Play It · Why This Exists · Why I'm Sharing This · What's Inside · How It Was Built · Architecture · Build from Source · Status · License
agent-wars-v2.16.0-2026-11-02-1-titled.mp4
Claude Sonnet 5.5, DeepSeek V4.1 Flash, GPT-6.1 Sol and Gemini 3.5 Flash-Lite in a four-way match over Western Europe: about two hours of play in three minutes, with only model think time removed (20-minute version, for easier viewing).
Before I started Agent Wars I'd been writing software by hand for a long time, but I knew very little about agentic development. This project was how I started learning about it.
I chose this approach because:
- I wanted a crash course in agentic development, on work I could afford to screw up. I especially wanted to learn what to expect as a codebase grows, from greenfield through features, bug fixes, and (eventual) replacement.
- It feels good to blow up commercial LLMs on imaginary battlefields, even if I'm paying their vendors for the privilege.
- For something new, I wanted LLMs to navigate real-world geography, planning combat, movement, and logistics on a hex map across many turns.
- Example: ever played Rogue or NetHack? Turns out LLMs have too, and they can use ASCII maps for spatial reasoning (see doc/ai-commander-prompts/strategic-prompt.md for more on this).
- For calibration, I built it on familiar ground (Electron and TypeScript, database development, and geospatial data), so I could catch bad agent output sooner.
I'm telling the story of how I built Agent Wars (and am still adding to it) in Standing Orders.
You can learn more about me on LinkedIn.
To offer what I've learned, and to give others a chance to blow up their (not) favorite LLMs, too.
Also: I don't intend to charge money for Agent Wars, now or ever.
I currently plan to:
- Throw features at this project (multiple human/LLM players, a diplomacy system, local LLM support, game save/load, etc.) until I've learned what I need to from this codebase.
- Then regenerate Agent Wars in a different language, framework, etc. (thinking of C#/Godot) and figure out what's next from there.
Download a build for Windows (x64), macOS (Apple silicon), or Linux (x64) from Releases. The builds are unsigned side-load builds, so Windows and macOS warn before the first launch. Each release lists SHA-256 checksums in SHA256SUMS.txt.
- Windows: unzip, then run
Agent Wars v2.25.0.exe. If SmartScreen stops it, choose More info, then Run anyway. - macOS: unzip, then open
Agent Wars v2.25.0.app. If macOS blocks it, open System Settings > Privacy & Security and choose Open Anyway. - Linux: extract the archive, then run
./agent-wars. That launcher handles Chromium's sandbox when the archive can't keepchrome-sandboxowned by root. On Ubuntu 23.10 and later, where AppArmor blocks unprivileged user namespaces, it starts without the sandbox and says so.
- When you first run Agent Wars, you'll see the New game screen. Explore the options and add AI opponents (up to 3).
- For each AI opponent, click on Select Model to enter your OpenRouter API key, reasoning, doctrine, and a model from Anthropic, Google, OpenAI, SpaceX/xAI, etc.
- My go-to playtesting model is Google Gemini Flash Lite (version 3.5, currently). A fast, inexpensive, tool-using model that fights reasonably well. It can also finish a typical game for <$1.
- Ollama/other local model support is on my radar (pun intended, I guess).
- Click Start game and play. See doc/how-to-play.md for the rest.
- When the game is over, the New game will include a summary of the results.
-
Only one copy of Agent Wars runs at a time. Launching it again brings the open window to the front.
-
At any time you can change models, stop and restart AI reasoning, or check on spend by opening the Command tab.
- When the AIs are done planning, the Ready button turns green. Click it to execute planned orders and start the next turn. You can play all you want with the AI disabled. This is a great way to get used to the controls, without burning tokens.
- Each opponent's OpenRouter key is stored locally in the Electron user-data directory. The screen receives a key only to fill that opponent's password field, and the key is not written to the activity log. Without a key and a model on at least one commander the app still runs, Start stays disabled, and that opponent makes no model calls.
See doc/how-to-play.md for more on how to play the game.
Formatted examples of one consultation are in the repo: doc/ai-commander-prompts/example-strategic-prompt.md and doc/ai-commander-prompts/example-tactical-prompt.md. One captured strategic reply is in doc/ai-commander-prompts/example-strategic-response.md.
To see how Agent Wars prompts the LLM, create a text file called .env in the game's working directory with the following:
AGENT_WARS_LOG_FULL_PROMPTS=1
AGENT_WARS_LOG_FULL_RESPONSES=1
AGENT_WARS_LOG_LEVEL=debug
AGENT_WARS_LOG_FULL_PROMPTScontrols prompt logging. Set to1,true,yes, oronto enable, anything else to disable.AGENT_WARS_LOG_FULL_RESPONSEScontrols OpenRouter response logging. Follows the same rules asAGENT_WARS_LOG_FULL_PROMPTS.AGENT_WARS_LOG_LEVELturns file-based logging on, at a specific level of detail. In addition todebug, there's alsotrace,info, anderror. Logging may impact game performance, particularly at thetraceordebuglevels.
The game's "working directory" is:
- Windows:
- When the game is started by double-clicking on the executable or a shortcut: wherever the executable is located.
- When the game is started from PowerShell or the Command Line: wherever the executable is invoked from.
- macOS: Not verified, but opening the app from Finder probably won't pick up
.env. I'll provide an update when I can. - Linux: Wherever the executable is invoked from.
When the .env file is present at runtime, the game will create one set of these files per opponent in the same directory. The number is aiIndexForSeatId of the seat being consulted. Opponent 1 writes debug-last-strategic-prompt-1.txt.
debug-last-openrouter-response-body-1.txt
debug-last-strategic-prompt-1.txt
debug-last-tactical-prompt-1.txt
debug-last-user-prompt-1.txt
debug.log
- debug-last-openrouter-response-body-N.txt: That opponent's last response from OpenRouter, including tool calls. A formatted example of one strategic reply is doc/ai-commander-prompts/example-strategic-response.md.
- debug-last-strategic-prompt-N.txt: That opponent's last system prompt sent during a strategic game. This doesn't include tool calls or results. A formatted example is doc/ai-commander-prompts/example-strategic-prompt.md.
- debug-last-tactical-prompt-N.txt: That opponent's last system prompt sent during a tactical battle. This also doesn't include tool calls or results. A formatted example is doc/ai-commander-prompts/example-tactical-prompt.md.
- debug-last-user-prompt-N.txt: That opponent's stock prompt suffix, sent after the strategic/tactical prompts.
- debug.log: Complete log output at the specified level of detail, including truncated tool calls. This file is appended to with every run, so it should be deleted when no longer needed.
See doc/hybrid-ai.md and doc/ai-tools.md for what goes into these prompts and how they're assembled and used.
Invading east Asia from southern Africa at the start of a game, with "fog of war" enabled (can't see enemy units, until they're close to your own). What could go wrong?
- A hybrid AI opponent. The engine pre-computes a briefing (an ASCII hex map, Markdown tables of units and threats, and attention flags) before it consults the model. Standing orders carry the plan forward on turns the model isn't consulted, and event callbacks decide when it is. Any OpenRouter model can play; one without tool calls plays without the planning tools. See doc/hybrid-ai.md and doc/ai-tools.md.
- Prompts as code. The prompts are assembled by builders in src/main/openRouter/promptSpec/, documented in doc/ai-commander-prompts/, and held to that contract by tests such as
consultationContract.test.ts,envelopeJsonSchema.test.ts, andvariantConformance.test.ts. - A real-Earth hex grid at two scales. Strategic play uses H3 resolution 1 on the global map, or 2 or 3 on one of the regional maps. Tactical battles sit three resolutions finer. Terrain, roads, place names, and climate come from public datasets through an offline Python pipeline (
scripts/terrain_pipeline/). The cell sizes and sources are under Hex Scales and Where the Data Comes From. - Simultaneous turns. Both sides plan, then the engine resolves air strikes, air drops, ranged fire, movement, ferry, and melee in a fixed phase order, with optional zoomed-in tactical battles. The rules are in doc/combat-rules-v3.md.
- Guardrails.
npm testbuilds the main process, then runs ESLint (with custom rules in eslint-rules/), a naming-convention check, a renderer type check, the main-process and tool tests (1847 tests), and a third-party-notices check. The renderer runs with context isolation, without Node integration, and under a Content-Security-Policy.
Every map is a grid of H3 cells, Uber's hierarchical hexagon index. A battle zooms in three resolutions, so one strategic hex contains 343 tactical cells (286 under one of H3's twelve pentagons), plus three rings of neighboring cells.
| H3 resolution | Used for | Average hex | Edge | About the size of |
|---|---|---|---|---|
| 1 | Global strategic map (842 hexes) | 609,800 km² | 483 km | Ukraine |
| 2 | Strategic map for 6 regions | 86,800 km² | 183 km | Austria |
| 3 | Strategic map for 17 regions | 12,400 km² | 69 km | Montenegro |
| 4 | Global battles | 1,770 km² | 26 km | Greater London |
| 5 | Battles on resolution 2 maps | 253 km² | 9.9 km | Malta |
| 6 | Battles on resolution 3 maps | 36 km² | 3.7 km | Macau |
Each of the 23 regional maps holds 257 to 352 strategic hexes. Those are the footprint totals in doc/region-summary-1.md: "South-Eastern Asia" is the smallest and "Southern Asia East" is the largest.
Cell areas and edge lengths are averages from the H3 library. The other counts come from the engine and the generated packs.
The offline pipeline samples rasters with rasterio and vector layers with Shapely, indexes the cells with H3, and ships the results as zipped JSON. PostGIS is part of that pipeline.
| Layer | What it drives | Source |
|---|---|---|
| Land cover | Forest, desert, arctic, and plains | EarthEnv 1 km consensus land cover, 12 classes |
| Topography | Mountain cells. The 50 km grids where a hex edge is at least 100 km, and the 5 km grids otherwise. | EarthEnv ruggedness, slope, and elevation from GMTED2010 |
| Climate | Each hex's weather in each month | CHELSA V2.1 1981-2010 monthly mean temperature and precipitation, averaged over a 10-arc-minute box |
| Water | Water, coast, and shoreline wetlands | Natural Earth 1:10m ocean and lakes |
| Coastlines | Hairline coast and lake shores on the map | Natural Earth 1:10m ocean and lakes |
| Borders | National borders from zoom 4, and state borders in the tactical view | Natural Earth 1:10m land boundaries and state and province lines |
| Place names | Continent, country, and state names on the map | Natural Earth 1:10m geography regions, countries, and states and provinces. The faces are bundled Noto Sans and Noto Serif. |
| Cities | Urban cells, and so the economy | Natural Earth urban areas, from 2002–2003 MODIS satellite data at 1 km |
| Ports and airfields | Where naval and air units are built and based | Natural Earth airports and ports |
| Roads and railroads | Infantry and armor enter a battle cell for half a point on a road and a third on a rail. | Natural Earth roads and railroads |
| Names and borders | Hex names, unit origins and flags, regional origin areas | Natural Earth countries, states and provinces, populated places, and marine areas |
| Landmasses | Which land is connected, so land units march within a landmass. | Natural Earth geography regions: continents, isthmuses, and islands of 2,000 km² or more |
Strategic hexes are assigned a per-month weather from that hex's mean temperature and its monthly precipitation, checked in this order (classifyWeatherMonth in weatherBonusRules.ts): "snow" at 0 °C or below, "rain" at 120 mm or more, "heat" at 23 °C or more, and mild when none of those match. Rain at 23 °C or above still counts as heat. The mean is the CHELSA 30-arc-second cells in that box, for land and water. Temperature is converted from kelvin. A centroid the raster does not cover copies the nearest sampled hex in that pack.
Credits and license terms are in THIRD-PARTY-NOTICES.md. Map place names use the bundled Noto Sans and Noto Serif faces listed there.
Production is based on real-world urban land cover: the Natural Earth urban areas in the table above, mapped from MODIS. Each strategic hex earns one point per turn for every intact urban cell inside it. The global map has 4,643 of those cells, on 283 hexes, counting cells that meet an urban area of scalerank 5 or lower (urbanOverlay in activeGameMap.ts). A queued unit spawns once its hex has saved enough points. On the global map each air-strike hit destroys 9 urban cells for good (strategicUrbanCellsDestroyedPerHit), so bombing a city cuts its output for the rest of the match.
| Unit | Cost | The hex also needs |
|---|---|---|
| Infantry | 20 | 1 urban cell |
| Armor | 40 | 2 urban cells |
| Air | 60 | 5 urban cells and an airport |
| Naval | 100 | 10 urban cells and a seaport |
| Fortification | 20 | One intact city cell. Not a unit, and not capped. |
| Credits | The map's infantry price | Adds 20 credits on every map. Not a unit, and not capped. |
Each regional map rescales costs, minimums, and strike size from its own urban counts, keeping the price ratio of 1:2:5:3:10 for infantry, armor, naval, air, and missiles, and the global share of hexes that can build each type. Infantry costs 60 in Western Europe and 10 in South America (doc/region-summary-1.md). A Credits item costs that map's infantry price and still adds 20 credits. Mercenary upkeep stays the global figures: infantry 3 (Advanced 5), armor 5 (10), naval 13 (25), air 8 (15).
A queue spends in the side's home, or on a hex that holds one of its units or fortifications. Elsewhere it pauses and loses its points at the end of the turn.
The opponent plans and manages its forces through six groups of MCP-style tools: engine services with JSON schemas that return the same result for the same game state, offered to the model through OpenRouter function calling. Each of these groups can be switched off from the Opponent tab.
| Group | What the model gets | Tools |
|---|---|---|
| Planning | Multi-turn routes and turn counts | plan_route, check_distance |
| Assessment | Threats, terrain, and occupants | assess_unit, assess_hex |
| Estimation | Analytic hit odds for a proposed attack | estimate_combat |
| Memory | Notes it saved on earlier turns | memory_read |
| Orders | The standing orders it has assigned | query_orders |
| Production | Income, build options, queues (including fortification and credits), and hiring | query_production, set_build_queue, query_mercenaries, hire_mercenaries |
Memory writes and standing-order changes travel in the model's JSON reply. The full catalog is in doc/ai-tools.md.
Every line of production code was written by coding agents, mostly in Cursor. I wrote the prompts that drove the agents and the rules they follow; the agents also wrote the plans and most of the documentation. All of it is in the repository:
- AGENTS.md: what every agent reads first, including which document wins a disagreement and what to update in the same change.
- .cursor/rules/: fifteen always-on coding rules, from reliable code and testing standards to file-size limits, naming, and secrets.
- .spec/completed/: the execution plans, audits, and verification records behind each change.
- doc/coding-prompts-1.md: the reusable prompt library. Its core cycle is four prompts: plan, audit the plan, implement, audit the implementation.
- doc/: the living product documentation, kept current with the code.
A trail to follow: the unit origin and country flags plan opens with ground rules for the executing agent, locked decisions, and verified facts. The code it produced is in src/main/unitOrigin/, with tests beside it (unitBirthOrigin.test.ts, unitBirthCellSelection.test.ts, and others).
I logged hours in Toggl from 1 Jan to 14 Sep 2026. The charts' 169 hours leave out 2.9 hours of planning and 6.5 hours of promotion. Cursor tokens are usage attributed to Agent Wars sessions by the window between milestone tags. Both records stop in September, before the October work on milestone 2.5.
Logged time and Cursor tokens by project stage, each as a share of its own total (169 hours and 5.9 billion tokens). Fixes, the work after the milestone 2.4 tag, took about a sixth of the time and a third of the tokens. The Fixes hours include some feature work.
The same totals by problem domain. Each milestone counts toward one domain, the subject of its execution plan. Game systems took the largest share of both, at 42% of the time and 40% of the tokens. Milestones 1.3 and 1.4 share one token window, split between geospatial and game systems by logged hours.
The same totals by milestone, from the core prototype (0.1 to 0.4) through tactical integration (2.4) and the fixes after it. Milestone 1.3 has no tag, so it shares a row with 1.4.
Event-driven consultation, as drawn for 2.4.0. In the drawing, the orange step is the one that calls the model, and it runs when a mandatory override or a callback the model subscribed to fires. The eight overrides along the bottom are still the ones the engine returns in 2.5.0, including the deadman consult after five turns. Every-turn mode consults during planning, and pre-computation no longer injects combat estimates.
The override list is the return of evaluateMandatoryOverrides, and the five-turn deadman is DEADMAN_TURNS, both in callbackEvaluation.ts. What ships now is in doc/hybrid-ai.md.
Prerequisites: Node.js 24 or later (.nvmrc pins 24) and npm 10 or later. Python 3 is used to extract the generated data during the build.
npm install
npm run build
npm start- Build: compiles the main process and preload with TypeScript (
dist/) and bundles the renderer with esbuild (static/renderer.js). Generated terrain data is extracted as part of the build. - Start: runs Electron; the window loads the renderer from
static/index.html. Game state is stored in SQLite through better-sqlite3 (a native module), in your Electron user-data directory. - Lint and test:
npm run lintruns ESLint onsrc/.npm run testruns the full check described under What's Inside. - Package:
npm run dist,dist:win,dist:linux, ordist:macbuilds with electron-builder (see .spec/completed/2026-03/2026-03-11-packaging.md). Releases are made as described in doc/releasing.md.
The generated terrain and region packs under data/generated/ are tracked, so building and playing need no GIS tools. To regenerate them:
npm run terrain:generateruns the metadata step, then the road/rail sides step. Related scripts:terrain:generate:landmass,terrain:generate:road-rail:high-fidelity, andterrain:generate:road-rail-vectors.npm run terrain:testruns the Python tests for the terrain scripts, andnpm run terrain:validatechecks the classification environment.
Setup, the Python CLIs, and troubleshooting are in scripts/terrain_pipeline/README.md. What the app loads at run time is in doc/terrain-pipeline.md.
The match basemap is the generated hillshade under data/generated/basemap/, not a live tile server. The app reads it through the agentwars-basemap protocol. The build commands are in scripts/basemap_pipeline/README.md.
- Version: 2.25.0, distributed as side-load builds only (no store, signing, or notarization).
- Progress: Phase 0 (hybrid AI validation) and Phase 1 (global strategic game) are complete. Phase 2 is complete through milestone 2.5 (regional game and rules enhancements), including tactical battles (2.1 to 2.4) and playtester UI fixes (2.45). Milestones 0.2 to 0.5 were a throwaway prototype that validated combat, tools, and the AI loop before the production baseline. The written plan is the development plan (v3.4).
- CI: lint and tests run on every push that changes code, and on demand (Linux). The three-platform packaging build runs on demand and drafts each release.
- Contributions: this is mostly a personal R&D project, but feel free to report issues (responses will be best-effort) or create a PR (acceptance is up to me).
- Security: to report a vulnerability or other security problem, see SECURITY.md.
Published builds, newest first. 2.8.0 through 2.8.4 shipped in 2.8.5. The version numbers jump at 2.7 and 2.11.
- 2.25.0 tells a commander to keep one city queued on credits, and names a city for a missile, a ship, or credits when one is worth building. A commander that can build a ship or a missile reads those rules before it owns one. Balanced and cautious commanders are told to strike enemy production their ground units cannot reach. Raise Options shows distance, nearby enemies, and chokepoints, and attention names one affordable raise and a missile that can launch.
- 2.24.0 names oceans, seas, gulfs, bays, straits, channels, and large lakes on the map. Zoomed out, ocean names are italic capitals. Closer in, seas and lakes appear once they are large enough on screen. The close view drops the ocean names and adds the smaller seas and lakes. The type is italic and a quieter blue than the land names. A water name moves aside for a land name, or for a water name already drawn.
- 2.23.0 points each AI commander on a regional map, when standing orders are on, at one enemy city. The ground force gathers, then assaults that city, while a home guard stays behind: one unit per nearby enemy ground unit, and never more than half the ground force. At the unit caps, that commander is told to bank credits and hire mercenaries, and to fortify only a city with an enemy nearby. An AI-only battle with a beat limit shows the beats left beside the beat number, in crimson at 5 or fewer.
- 2.22.0 discards a paused queue's production points at the end of the turn. A queue that is still building keeps the points it could not spend. The pause is outside your home with none of your units or fortifications on the hex, a city whose cells are all fortified, or a unit type at its cap. The turn report names that queue on the turn it pauses. A build-only popup is 200 px wide, and hire goes to 280 px.
- 2.21.3 puts a side's visible missile strikes on one line and its fortification hits on one line, both naming the hexes by code. A battle beat has the fortification line and no missile line. A commander is shown up to ten prior turns of notes.
- 2.21.2 waits one extra zoom level before a country name appears, and shows a state or province name when that area is large enough on screen. Continent names grow while country names are on the map, and country names grow in the close view that draws states. A larger name moves off a smaller one and returns when its original spot is clear. Continent names drawn with countries, and national borders, are four fifths strength. Country names drawn with states, and state borders, are three fifths.
- 2.21.1 lets an AI-only battle stop after a chosen number of beats, 30 unless you pick another. Unlimited removes that limit, and None turns it off. Reaching it ends the battle and shows how many beats it ran. While turns advance on their own, that notice stays for 3 seconds. While you watch every side, Production and Forces add up the sides still playing. Fog of war, Sight cues, and Auto-start AI sit together under Other.
- 2.21.0 draws the map from a shaded-relief pack on this computer, and draws land with more contrast so mountains read more clearly. Monthly weather comes from CHELSA V2.1 1981–2010, including ocean hexes. Four map themes recolor land, water, roads, and rails. A hairline follows coasts and lake shores, national borders and country names appear together, and the detail view adds state borders and state names. A city hides a state name it shares. While the new-game screen is open, names and borders follow that preview. A save still opens, and its weather follows this climate.
- 2.20.0 removes a vertical line of city cells that a new game drew down the 180° meridian. Those cells were counted as cities because the map seam wrapped them across the world. A new game on Australia & New Zealand or Eastern Europe uses the corrected city counts: Australia & New Zealand infantry costs 9, and Eastern Europe's strike threshold is 8 city cells. A save keeps the city cells and prices it was created with.
- 2.19.0 draws each commander's strategic map around its units, visible enemies, cities, and listed targets, and groups idle build hexes by what they can still queue. A move past this turn's budget becomes a march when standing orders are on, and a move onto a unit's own cell holds that unit. A battle that crosses the 180° meridian draws as one area. Starting the game again brings the open window to the front, and preparing a commander's briefing freezes the window less.
- 2.17.0 lets an air unit carry one infantry unit and either drop it within strike range or ferry it through your airports. Resting on a ranged target shows Kill, Hurt, and Loss, and a commander's options use those same chances.
- 2.16.0 shortens commander prompts. A tactical briefing lists the odds of each fight it already shows. Planning stops after 20 tool rounds, then asks once more for orders with the tools withheld. A planning round can submit orders without a tool call. A knocked-out side shows the turn in parentheses, and a fortification loss names the place and how many hits it absorbed.
- 2.15.0 lets each commander choose an OpenRouter host, gives a model call twice as long before it times out, and shows each commander's think time on the result screen.
- 2.14.0 lets you name your side and each opponent, draws lines to the units an observing commander could see, shows your unit counts from the top bar, and keeps units that would trade hexes from slipping past each other.
- 2.13.0 lets an observing match fight tactical battles with AI commanders, frames the visible units while turns advance on their own, names strategic units destroyed in a battle, and names the app to OpenRouter on chat and model-list requests.
- 2.12.0 adds fortifications, a credit treasury, and mercenary hiring. A missile destroys a cell on a roll of 10 or less. Open sea inside a coastal hex stays water in a battle, and a launch, a strike, and a ranged shot use the same arrows as a queued order.
- 2.10.0 adds ballistic missiles.
- 2.9.0 adds player-facing save and load. See doc/save-files.md.
- 2.8.5 names who holds a hex with that side's short name. The same build includes:
- 2.8.4 replaces an unreadable short home name with a letter form of that name.
- 2.8.3 keeps each side's turn report to the hexes that side lost. The 2.8.2 report had also listed hexes taken.
- 2.8.2 opens the new-game screen at the top.
- 2.8.1 lines up the commander popover and collapses the console when a match starts.
- 2.8.0 adds matches of two to four sides, each AI side with its own commander.
- 2.6.0 redesigns the layout: a top bar, a console docked on the right, a selection panel on the map, and a new-game panel docked at the left.
- 2.5.2 names armored movement and blocked terrain on a march preview, and the strategic prompt names the loaded map.
- 2.5.1 stops a running plan when Run is turned off or the model changes, lets you start a new game during a match, and leaves a battle while a world-map plan that is already running keeps going.
Source code written for Agent Wars is under the MIT license. Reuse it, and keep the copyright notice and the license text with the copy.
Third-party software, vendored files, and the generated earth data under data/generated/ keep the terms in THIRD-PARTY-NOTICES.md. The terrain uses EarthEnv consensus land cover, which is CC BY-NC 4.0. That term prevents commercial use of the application as distributed.











