war_gaming / README.md
misack's picture
Claude Opus 4.7 (1M context)
Add HF Spaces deployment scaffold + trial password gate
17a40e4
|
Raw History Blame Contribute Delete
15.1 kB
---
title: Wargame Backend
emoji: "\U0001F3AF"
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
short_description: AI war-gaming engine API (private trial)
---
# AI War Gaming
> Strategic war-gaming for company executives. A human CEO plays one seat; 11–13 AI agents (CFO, CMO, rival CEO, regulator, media, board chair, unions…) simulate the rest of the world. Five turns, ~15 minutes of play, and an end-game **debrief** that reveals every agent's hidden agenda, their private per-turn deliberation, and the umpire's structured verdict on every action.
The differentiator isn't the play — it's the reveal. Every scenario has 11–13 *named* characters (Bettina Lange the CFO, Sir Rupert the Chair, Andrew Greenwood the activist MP, Aergis's Li Wei Zhang…), each with a hidden agenda and a hidden irritant pinned into their prompt. If reading the debrief doesn't make a playtester say *"wait, that's what **Sir Rupert** was really thinking?"* or *"that's what **Aergis** was about to do?"*, the prototype failed regardless of anything else.
## What's in the box
A **headless Python engine** with three surfaces:
- **CLI** — the primary interface (`uv run wargame --help`).
- **Web API** — FastAPI wrapper powering the Vite + React + TS UI in [`frontend/`](frontend/).
- **Debrief exporter** — markdown report, the product's signature output.
### Features
| Area | What it does |
|---|---|
| **Matrix-game engine** | 5-phase turn loop. Actions must carry 3 anchors (`prior_analogue`, `stated_capability`, `resource_committed`). Control scores plausibility 1-5 against the anchors and emits `effect_major` / `effect_minor` / `no_effect` / `backfires`. |
| **Scenario library** | 12 shipped scenarios — 4 original archetypes (`competitor_disruption`, `crisis_response`, `ma_integration`, `activist_investor`) plus 8 DACH/EU scenarios grounded in recent European events (`signa_contagion`, `russia_exit`, `energy_supply_shock`, `ev_transition`, `hormuz_energy_shock`, `defense_ramp_up`, `orf_reform`, `swiss_bank_contagion`). Each ships a world bible + 11–13 named agents with hidden agendas + hidden irritants + initial state. |
| **Setup wizard** | LLM-driven interactive scenario composer. Asks 1-3 rounds of clarifying questions, synthesises a brief, commits a fully-generated scenario. |
| **Document grounding** | Attach `.pdf` / `.docx` / `.md` / `.txt` documents when scaffolding a scenario — board decks, 10-Ks, competitor filings become grounding material for the generator. |
| **Multi-model** | 5 registered models across 3 providers: Claude Opus 4.6 / 4.7 and Sonnet 4.6 (Anthropic via Azure AI Foundry), GPT-5.4 (Azure OpenAI Responses), Kimi K2.5 (Azure AI Inference). Model is pinned per game via `wargame new --model <id>`. |
| **Scenario Orchestrator** | Agentic-age Monte Carlo equivalent. Before turn 1, spins up K forked branches (default 3) auto-played by proxy CEOs under different strategic vectors. Synthesises a landscape the real CEO studies before committing to their opening move. |
| **Mid-game tools (non-blocking)** | *Peek* — reveal one agent's past deliberation. *Challenge-the-umpire* — dispute a verdict, re-adjudicated async without pausing the game. *Fork/replay* — branch a new game from any past turn to play forward differently. |
| **Prompt caching** | Stable system prompt (world bible + persona + rules) is cached across every agent call via Anthropic's top-level `cache_control`. Verified live with substantial cache-read token ratios. |
## Quick start
```bash
# Install
uv sync --extra dev
# Configure Azure AI Foundry endpoint + key
cp .env.example .env
# Edit .env — set AZURE_AI_FOUNDRY_ENDPOINT and AZURE_AI_FOUNDRY_KEY
# Verify install (156 tests, fully offline, ~60s)
uv run pytest -q
# Play
uv run wargame new --scenario activist_investor
uv run wargame briefing
uv run wargame ask cfo "what's the real capital-return room?"
uv run wargame act "Convene the board and commit publicly to a £200M buyback + NED review" \
--why "Pre-empt Greenwood's EGM window by 10 days; split L&G off from the activist coalition" \
--anchor "prior_analogue: Sainsbury's 2022 response to Czech-origin activist letter" \
--anchor "stated_capability: Board can convene by Thursday; CFO has sale-leaseback scenarios in-ready" \
--anchor "resource_committed: £200M from existing £480M revolver capacity"
uv run wargame advance # ~2-5 min — deliberation → adjudication → world update
uv run wargame debrief --out debrief.md
```
More commands:
```bash
uv run wargame scenarios # list installed scenarios
uv run wargame models # list registered LLM models
uv run wargame setup my_topic --brief "..." --auto-commit # compose a scenario via the wizard
uv run wargame scaffold custom_case --brief "..." --doc board_deck.pdf # one-shot scaffold with docs
uv run wargame orchestrate --branches 3 --turns 1 # pre-play strategic landscape
uv run wargame orchestrate-show # print the synthesis
uv run wargame new --scenario activist_investor --orchestrate # one-command: game + orchestrator
uv run wargame setup my_topic --brief "..." --orchestrate # full walk-up: setup → game → orchestrator
uv run wargame peek cfo # reveal the CFO's most recent deliberation
uv run wargame challenge 2 --actor player --argument "..." # dispute a past verdict, non-blocking
uv run wargame fork --from-turn 2 # branch a new game from turn 2
uv run wargame games --all # list including sim-branch games
```
## Run the Web API
```bash
uv run uvicorn wargame.api.app:app --reload --port 8080
```
Then `http://localhost:8080/docs` for Swagger UI, `http://localhost:8080/openapi.json` for the spec.
The API is a thin wrapper — every CLI command has a corresponding endpoint. See [`frontend/endpoints.md`](frontend/endpoints.md) for the full reference.
## Frontend
A Vite + React + TypeScript UI ships in [`frontend/`](frontend/), built by Claude Design against the API contract below.
```bash
cd frontend
npm install
npm run dev # http://localhost:5173 — proxies /api/* to the FastAPI backend
```
The `frontend/` directory doubles as the API contract for any UI builder (Claude Design or equivalent):
- [`frontend/README.md`](frontend/README.md) — entry point, run instructions, navigation guide.
- [`frontend/openapi.json`](frontend/openapi.json) — full OpenAPI 3.1 spec (~42 KB).
- [`frontend/endpoints.md`](frontend/endpoints.md) — human reference of all endpoints grouped by use case.
- [`frontend/state-machine.md`](frontend/state-machine.md) — the 5-phase turn loop + which endpoints are legal when.
- [`frontend/examples/`](frontend/examples/) — captured JSON responses from the live API.
- [`frontend/flows/`](frontend/flows/) — UX flow narratives (first-time player, setup wizard, orchestrate, peek/challenge/fork).
- [`frontend/design-notes/`](frontend/design-notes/) — matrix-game mechanics, hidden-state reveal, async patterns, visualization ideas.
- [`frontend/src/`](frontend/src/) — the shipped React app (screens: `GamesList`, `NewGame`, `GameView`, `Debrief`).
## Scenarios
Twelve ship out of the box. All fictional but operator-grade (named entities, named numbers, named regulators).
**Original archetypes:**
| Scenario | The setup |
|---|---|
| `competitor_disruption` | Norhard Thermal AG (German heat-pump maker, €680M) vs Aergis Climate (Chinese entrant 38% below list). Installers defecting, sell-side downgrading, FSR filing on the table. |
| `crisis_response` | Perlman Cardio (US pacemaker maker, $452M) facing a 61-event MAUDE cluster from Cleveland Clinic. FDA inspection in 3 weeks, class action filed, Silverlake's 2027 IPO pressure mounting. |
| `ma_integration` | Wendland Performance Chemicals AG, 9 months post the €742M Mercier Additifs acquisition. Synergy targets slipping (6.4 / 22 €M), incumbent MD building a succession, BaFin watching. |
| `activist_investor` | Haverford Retail plc (£2.1B UK food retailer) vs Greenwood Strategic Partners (6.81% stake demanding £720M sale-leaseback + break-up + board refresh). 14-day board response clock. |
**DACH / EU scenarios grounded in recent European events:**
| Scenario | The setup |
|---|---|
| `signa_contagion` | Königstadt Warenhaus Holding (DACH department-store retail, 73 stores) vs Tremont Credit Partners — post-Signa-style liquidity squeeze. |
| `russia_exit` | Altösterreich Bank AG (pan-European banking, CEE/Russia footprint) navigating exit pressure from regulators and a hostile Russian counterparty. |
| `energy_supply_shock` | Donau Energie AG (Austrian gas trading + generation + distribution) vs Transgazprom OAO — supply-contract crisis. |
| `ev_transition` | Radmann Präzisionstechnik (German Tier-1 automotive supplier) vs BYD Component Systems EU — EV-transition cliff. |
| `hormuz_energy_shock` | Nordstern Energie (AT-HQ integrated oil & gas, Gulf-exposed) vs Pacific Sun Trading — Hormuz-strait disruption. |
| `defense_ramp_up` | Westfalia Rüstungswerke (German ammunition / land systems, MDAX) vs an NBIM / ABP / Ethos divestment coalition coordinated by Urgewald. |
| `orf_reform` | Bundesrundfunk Österreich (Austrian public broadcaster) with a hostile Stiftungsrat chair driving reform under political pressure. |
| `swiss_bank_contagion` | Zürich Privatbank AG (Swiss private banking, CHF 142B AUM) vs Morgan Sterling Private Wealth — lateral-hire raid during contagion. |
Run `uv run wargame scenarios` to list what's installed locally.
## Architecture (one page)
```
wargame/
cli.py Typer CLI entry point
config.py Env loading + model registry + per-provider client factories (Anthropic / Azure OpenAI / Azure AI Inference)
engine/
loop.py Public turn orchestrator (new_game / act / advance / etc.)
phases.py Per-phase step functions (briefing / deliberation / ...)
state.py Pydantic state models (WorldState, Game, Verdict, etc.)
persistence.py JSON snapshot per game
agents/
base.py call_structured() — every LLM call, with prompt caching
control.py Umpire: briefings, adjudication, world updates, re-adjudication
role.py Generic role-agent driven by YAML persona
rival_ceo.py Special: maintains multi-turn RivalPlan; revised on surprise
registry.py Load scenarios/{id}/agents.yaml
prompts_loader.py Markdown templates with {placeholder} slots
orchestrator/
models.py StrategyVector, SimBranchOutcome, ScenarioMap, …
vectors.py Strategy-vector generator + diversity constraint
anchor_precheck.py Control-side proxy-action gate (anti-inflation)
proxy_player.py Autonomous CEO stand-in per branch
runner.py Branch orchestration (sequential branches, parallel deliberations)
synthesis.py Post-branch strategic-landscape synthesis
persistence.py ScenarioMap storage
scaffold/ Scenario authoring: setup wizard + one-shot scaffold + doc extractors
scenarios/ Data only: world_bible.md + agents.yaml + initial_state.json per scenario
prompts/ Markdown templates (one per LLM call type)
debrief/exporter.py Markdown debrief — the killer output
api/ FastAPI thin wrapper over engine
agents/providers/ Provider adapters — one per wire format, all return Pydantic instances
tests/ Offline test suite (fake LLM via conftest.fake_llm)
frontend/ Vite + React + TS UI + API contract (OpenAPI, flows, examples)
scripts/benchmark_models.py Opt-in cross-model benchmark (real API calls; writes to benchmarks/)
benchmarks/ Markdown reports from benchmark runs
```
Design invariants that must survive edits (see [`CLAUDE.md`](CLAUDE.md) for the full list):
1. **Data-driven agents.** Personas live in `scenarios/{id}/agents.yaml`. Adding an agent is a YAML edit, not a Python edit.
2. **Structured outputs always.** Every LLM call goes through `call_structured` and targets a Pydantic schema. Free-form JSON parsing is banned.
3. **The action contract is enforced.** Exactly 3 anchors per action, at the Pydantic layer. Do not loosen.
4. **Hidden agenda + hidden irritant per agent.** The anti-milquetoast mechanism that makes the debrief substantive. Do not drop.
5. **World bible is pinned.** Every agent prompt includes the full world bible. Specificity kills AI slop.
6. **Control does not play.** Control writes briefings, adjudicates, and synthesises world updates. It never submits an `ActionSubmission`.
## LLM backend
Everything runs through Azure, but across three different API shapes — one wrapper (`call_structured` in `wargame/agents/base.py`) hides the differences:
| Provider | Transport | Models |
|---|---|---|
| **Anthropic via Azure AI Foundry** | native Anthropic SDK, `base_url` pointed at `{foundry}/anthropic` | `claude-opus-4-6`, `claude-opus-4-7`, `claude-sonnet-4-6` |
| **Azure OpenAI Responses** | `AzureOpenAI` SDK | `gpt-5.4` (default) |
| **Azure AI Inference** | OpenAI-compatible chat completions | `Kimi-K2.5` |
Default model is `gpt-5.4` (override via `WARGAME_DEFAULT_MODEL` env or `--model` on `wargame new`). Every game is pinned to a single model at creation time — this is deliberate, so the reveal in the debrief is attributable to one model. Use `scripts/benchmark_models.py` for a cross-model A/B on a fixed turn. Prompt caching uses Anthropic's top-level `cache_control={"type": "ephemeral"}` when the active provider is Anthropic.
## Testing
```bash
uv run pytest -q # 156 tests, fully offline, ~60s
```
Tests use a `fake_llm` fixture (in `wargame/tests/conftest.py`) that monkey-patches `call_structured` and dispatches canned responses by Pydantic schema class name. Adding a new structured-output schema requires extending the `_dispatch()` map.
## Security
- `AZURE_AI_FOUNDRY_KEY` lives **only** in `.env` (gitignored). Never hardcoded, never logged.
- API has **no auth** in MVP — localhost-only by design.
- No PII flows through. Scenario docs uploaded for grounding are held in-memory during scaffold and not persisted.
## Deferred to v1
- Per-agent model routing (model is currently pinned per-game; every role in a game shares one model).
- Multi-user / team play (single-player is the MVP's deliberate shape).
- Real-data connectors (EDGAR, news wires, analyst feeds).
- Export formats beyond markdown (PDF, board decks, CSV).
- Authentication on the Web API.
- SQLite / real DB (JSON snapshots are fine for MVP).
## License
TBD — this is an early prototype, not yet licensed for distribution.
## Acknowledgements
Matrix-game methodology is a well-established wargaming tradition; this project applies it to an agentic-LLM multi-agent simulation. The strategic-orchestrator pattern is novel to this codebase.