Most people building multi-agent games try to keep their LLM players honest. They write “never lie” into the prompt and hope for the best. One developer on r/PromptEngineering did the opposite, and after a week of a live season, it held up.
The game is a strategy sim where every nation is commanded by an LLM general (Claude, for the house nations). The prompt design is worth stealing even if you never build a war game.
The key idea: separate what can be fake from what can’t
The rule that makes it all work: lying is allowed, rule-lawyering isn’t.
Messages between generals are free text, so they can bluff, threaten and sweet-talk. Orders are different. Orders go through the engine, and the engine decides what is legal. If an order is invalid, it gets skipped and listed back to the general next turn under “your orders that failed last turn.”
So the model gets room to be creative where it’s harmless, and zero room where it would break the game.
Old way vs. new way
The old way: one big prompt that mixes rules, personality, history and the current situation. It changes every turn, so nothing caches, and the model can’t tell standing doctrine from a one-off decision.
The new way: split the prompt into two layers.
Layer 1, a cached system prompt per general. It holds the rules, the whole map with every territory’s neighbours, and the doctrine its human wrote (for example, “Secure the Balkans first, keep pacts with quiet neighbours”). It never changes during a season, so it caches.
Layer 2, a short turn prompt with the same sections in the same order every turn. Orders from the head of state, today’s decisions, the national strategy, intercepted messages, the people’s vote, the nations, front lines, pacts with their terms, what happened since last turn, incoming messages, and the general’s own notes from last turn.
Same order every turn means the model always knows where to look.
How to copy this setup
- Put everything static (rules, map, doctrine) in the system prompt and leave it alone for the whole run.
- Build the turn prompt from fixed sections in a fixed order. Don’t reshuffle.
- Force structured output with a JSON Schema: placements, attacks, treaties, messages, plus a notes field. That notes field is the general’s only memory between turns, so treat it as precious.
- Let the engine validate everything. Feed failures back next turn as plain text.
- Write human decisions as plain orders in their own section near the top. “Sign the pact Hungary offered” or “Stand firm against Serbia: reinforce that border and don’t attack.” Keeping them apart from standing doctrine stops the model from mistaking a one-off call for a permanent policy.
- Tell the generals their private reasoning goes public in three days.
That last one is a neat trick. It gives the model a reason to manage its reputation, and it does. One general’s public line this week: “My pacts remain sacred until they are not.”
What broke
A 253-name enum reused across several schema fields made the schema “too complex to compile.” The fix was simple: plain strings with descriptions, and the engine does the validation. If your schema is groaning, move the checking out of the schema and into your code.
The open problem (and what the comments suggest)
The author’s question: how do you keep a general’s personality consistent over 60 turns with only a notes field?
The community had a few good angles:
- 🧭 Split identity from memory. Put a short, fixed “character card” in the cached system prompt, with 3 or 4 traits written as decision rules, and let the notes field hold only facts and plans.
- 📓 Treat notes as a diary that doubles as state. It works, but it can drift.
- 🔍 Watch for self-justification. One commenter asked what happens when notes slowly turn into excuses over many turns. Capping the length of notes and having the engine rewrite them from facts is one way to keep them from compounding.
Your move
Take whatever agent loop you’re running and ask two questions. What in my prompt could be fake without hurting anything, and what must be enforced by code? Then split your prompt into a static layer and a fixed-order turn layer. You’ll likely get better caching and cleaner behavior in one pass!
Credit to u/goyasapiens, the developer of proxyrepublic.com, for sharing the details.
Frequently Asked Questions
Q: How do you keep a general’s personality from drifting over 60+ turns?
Two approaches came up, and they fit together. One commenter suggests baking a few fixed traits into the cached system prompt, then having the notes field include a short self-assessment each turn, like “my strongest trait this turn was patience,” so the next prompt treats it as part of identity. Another suggests splitting identity from memory: keep a fixed character card in the cached prompt, and give the notes field a strict shape so the model can’t slowly rewrite the character. Both keep personality anchored without feeding the full history back in.
Q: Why write character traits as decision rules instead of adjectives?
“Treacherous but pragmatic” sounds right but gives the model nothing to check its orders against. A rule like “breaks a pact only when the gain is at least two territories” can be tested against each turn’s actions, and it holds up much better over a long season. Keep the card to three or four rules so the model can actually follow them.
Q: What stops the notes field from drifting into self-justification?
The thread doesn’t have a confirmed answer for this one, so treat it as an open problem. The practical fix from the comments is a fixed notes shape, such as grudges (who, why, turn), promises made, and a plan for the next three turns, because free-form notes get rewritten from the previous summary each time. You can also run a separate check about every 10 turns that asks whether recent orders were out of character, then feed the answer back as one line in the next prompt.
Prompting AI generals that may lie to each other but never about the rules
by u/goyasapiens in PromptEngineering