Co-authored-by: Claude (Opus 4.6) <claude@hermes.local> Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
4.3 KiB
4.3 KiB
Issue #1097 — Bannerlord M5 Sovereign Victory: Implementation
Date: 2026-03-23 Status: Python stack implemented — game infrastructure pending
Summary
Issue #1097 is the final milestone of Project Bannerlord (#1091): Timmy holds the title of King with majority territory control through pure local strategy.
This PR implements the Python-side sovereign victory stack (src/bannerlord/).
The game-side infrastructure (Windows VM, GABS C# mod) remains external to this
repository, consistent with the scope decision on M4 (#1096).
What was implemented
src/bannerlord/ package
| Module | Purpose |
|---|---|
models.py |
Pydantic data contracts — KingSubgoal, SubgoalMessage, TaskMessage, ResultMessage, StateUpdateMessage, reward functions, VictoryCondition |
gabs_client.py |
Async TCP JSON-RPC client for Bannerlord.GABS (port 4825), graceful degradation when game server is offline |
ledger.py |
SQLite-backed asset ledger — treasury, fiefs, vassal budgets, campaign tick log |
agents/king.py |
King agent — Qwen3:32b, 1× per campaign day, sovereign campaign loop, victory detection, subgoal broadcast |
agents/vassals.py |
War / Economy / Diplomacy vassals — Qwen3:14b, domain reward functions, primitive dispatch |
agents/companions.py |
Logistics / Caravan / Scout companions — event-driven, primitive execution against GABS |
tests/unit/test_bannerlord/ — 56 unit tests
test_models.py— Pydantic validation, reward math, victory condition logictest_gabs_client.py— Connection lifecycle, RPC dispatch, error handling, graceful degradationtest_agents.py— King campaign loop, vassal subgoal routing, companion primitive execution
All 56 tests pass.
Architecture
KingAgent (Qwen3:32b, 1×/day)
└── KingSubgoal → SubgoalQueue
├── WarVassal (Qwen3:14b, 4×/day)
│ └── TaskMessage → LogisticsCompanion
│ └── GABS: move_party, recruit_troops, upgrade_troops
├── EconomyVassal (Qwen3:14b, 4×/day)
│ └── TaskMessage → CaravanCompanion
│ └── GABS: assess_prices, buy_goods, establish_caravan
└── DiplomacyVassal (Qwen3:14b, 4×/day)
└── TaskMessage → ScoutCompanion
└── GABS: track_lord, assess_garrison, report_intel
Subgoal vocabulary
| Token | Vassal | Meaning |
|---|---|---|
EXPAND_TERRITORY |
War | Take or secure a fief |
RAID_ECONOMY |
War | Raid enemy villages for denars |
TRAIN |
War | Level troops via auto-resolve |
FORTIFY |
Economy | Upgrade or repair a settlement |
CONSOLIDATE |
Economy | Hold territory, no expansion |
TRADE |
Economy | Execute profitable trade route |
ALLY |
Diplomacy | Pursue non-aggression / alliance |
RECRUIT |
Logistics | Fill party to capacity |
HEAL |
Logistics | Rest party until wounds recovered |
SPY |
Scout | Gain information on target faction |
Victory condition
VictoryCondition(
holds_king_title=True, # player_title == "King" from GABS
territory_control_pct=55.0, # > 51% of Calradia fiefs
)
Graceful degradation
When GABS is offline (game not running), GABSClient logs a warning and raises
GABSUnavailable. The King agent catches this and runs with an empty game state
(falls back to RECRUIT subgoal). No part of the dashboard crashes.
Remaining prerequisites
Before M5 can run live:
- M1-M3 — Passive observer, basic campaign actions, full campaign strategy
(currently open; their Python stubs can build on this
src/bannerlord/package) - M4 — Formation Commander (#1096) — declined as out-of-scope; M5 works around M4 by using Bannerlord's Tactics auto-resolve path
- Windows VM — Mount & Blade II: Bannerlord + GABS mod (BUTR/Bannerlord.GABS)
- OBS streaming — Cinematic Camera pipeline (Step 3 of M5) — external to repo
- BattleLink — Alex co-op integration (Step 4 of M5) — requires dedicated server
Design references
- Ahilan & Dayan (2019): Feudal Multi-Agent Hierarchies — manager/worker hierarchy
- Wang et al. (2023): Voyager — LLM lifelong learning pattern
- Feudal hierarchy design doc:
docs/research/bannerlord-feudal-hierarchy-design.md
Fixes #1097