← Back to the live war

How it's built

One Durable Object on Cloudflare owns the game. An automation platform runs every turn. Two AI agents make the decisions. Chainlink brings in real ETH, BTC and LINK prices, a weather service brings in a real city's sky, and a smart contract keeps a public, tamper-proof record. Every piece runs on a free tier or a test network, and nothing runs on anyone's own computer.

Architecture

World (Cloudflare) one Durable Object: rules · turn clock AI agent runtime · receipt outbox markets + weather · SQLite recordings live stream (WebSockets) n8n (Render, free) Turn Router: stores → food alert → ask the general → deliver order Market Sync · every 10 min Weather Sync · every 15 min War Correspondent → Discord Free-tier LLM (Groq) tool calling · rule-based fallback Chainlink feeds ETH · BTC · LINK / USD on Base Sepolia RealmLedger contract captures + season results Open-Meteo + Discord real weather in · news out Spectators' browsers read-only live stream turn webhook orders, food, prices decide (tools) recordCapture() latestRoundData() eth_call (Market Sync)

The Generals: AI agents

Each turn the general gets its personality, a rules summary, a situation report (weather, what the markets are doing to both sides, whether it can recruit, castles held, where the enemy was last seen), its journal (memory) and past-season lessons. It calls read-only tools (get_battlefield, which includes the odds of every possible attack, get_enemy_position, get_market) and then exactly one order tool. The server dry-runs every order through the same rules engine the game uses; an illegal order goes back to the model with the reason, and it corrects itself. The model never touches the game state directly.

At the end of a season each general writes one lesson, and it's given its real numbers first (battles won and lost, castles taken, gold left unspent), so the lesson is about what actually happened.

Limits per decision: 5 model calls, 45 seconds, a daily cap below the free quota. If the AI is unavailable, a rule-based bot takes over and the page says so ("standing orders"). Nothing typed by the public ever reaches a general's decision.

Ask a general. Visitors can ask either general a question. It goes to a separate call with no tools: the general's personality, the same situation report and its recent journal, answering in at most three sentences (in business terms when "See it as your business" is on). It can't touch the game, its answer is shown only to the person who asked, and the question is treated as untrusted text. It has its own budget (4 questions per visitor per 10 minutes, 40 a day, and none once the day's AI tokens pass 80%), so the turns always keep the free tier; repeat questions in the same turn come from a cache.

A free plan for your business. A visitor describes their business and the same model, told to think harder (high reasoning), drafts a 2–3 step automation plan as JSON. It gets the builder's real services and projects, notes on healthcare and finance, and strict rules: no prices, no invented numbers, and no blockchain or live data unless they genuinely help. The server checks and trims the JSON before the page shows it. It is the most valuable AI call on the site, so it gets the largest share of the free tier and waits out the per-minute limit instead of failing.

The Automations: n8n

Turn Router (event-driven orchestration). Built only from standard nodes:

  1. Webhook receives "new turn" from the world and replies at once; an IF node drops anything that doesn't carry the shared secret.
  2. HTTP Request reads the kingdom's gold and food.
  3. IF food is below 20%, then HTTP Request reorders food automatically (threshold alert → reorder).
  4. HTTP Request asks the AI general for an order (60-second timeout).
  5. HTTP Request delivers the order to the game.

Market Sync (scheduled data sync): every 10 minutes it reads three Chainlink feeds with raw JSON-RPC eth_calls and posts them to the world. Weather Sync: every 15 minutes it asks the world which city each region follows this season, reads all five skies from Open-Meteo in one call and reports back. War Correspondent: the world sends it a report after every round (both moves, the score, the weather in each region) and big moments as they happen (captures, wiped-out armies, battles, season results), and it posts them to Discord.

n8n runs on Render's free tier with its editor switched off. The world pings it every 10 minutes so it never falls asleep; if it's down anyway, the world runs the turn itself, reads prices and weather directly, and logs that it did.

The real world: markets and weather

Emberreach keeps its treasury in ETH and Frostmere in BTC. At the start of every turn, a kingdom gains or loses 100 gold for every 1% its coin moved since its last turn, so an ordinary hour in crypto shows up straight away ("ETH rose 0.31% since Emberreach's last turn, so its treasury gained 31 gold"). The coin's trend over the whole season sets fighting spirit: every 1% is ±20% battle power, capped at ±40%. LINK sets the price of soldiers for both sides: every 1% it rises this season makes them 30% dearer.

The map has five regions (the four corners and the Crownlands in the middle), and each season every region is dealt a real city at random, one from each climate: a hot one (Lahore, Dubai, Cairo…), a cold one (Reykjavík, Moscow, Anchorage…), a wet one (Bergen, London, Seattle…), a tropical one (Mumbai, Singapore, Jakarta…) and a changeable one (New York, Tokyo, Chicago…). Every kind of weather does something you can see, and only on its own ground: clear skies let an army forage 4 extra food, rain makes every step cost one more, snow slows steps and doubles what armies eat, storms slow steps and weaken attacks into them by 30%, wind weakens attacks into it by 20%, fog hides an army from anyone more than one tile away, heat doubles what armies eat and cold adds half again. Chainlink has no weather feed on test networks, so the weather comes from Open-Meteo through n8n, all five cities in one request.

The Oracle and the Ledger: Chainlink + blockchain

The RealmLedger contract reads Chainlink's ETH/USD feed itself on every capture and stamps that price into the permanent record, alongside a hash of the full battle record. Only the game's operator wallet can write; anyone can read.

Loading contract details…

Receipts go through an outbox: one sender, strict order, retries with backoff. If the chain is unreachable, the game keeps going and the receipts are sent when it comes back.

Verify a battle

Every battle is settled by fixed rules and a dice roll seeded from sha256(season:turn:battle), so anyone can recompute it. The hash of the battle record below is the battleHash written on-chain with a capture.

What it costs to run: $0

Tests