Squad coordination
Two agents share a Blackboard fact to coordinate without stomping each other. Per-unit planners stay independent.
[ Example ]
Squad coordination — two-agent assault
Two agents share a coordination signal so they don't both flank the same side of a target. This is the canonical "how do I make agents not stomp each other?" answer — and it works without any multi-agent planner. Intent Forge plans for one agent at a time; coordination lives at the fact layer.
The setup
Two Assailant pawns + one Target pawn. The assailants want to attack
the target from opposite sides.
- Without coordination: both assailants pick the same flank (whichever is geometrically closest). They bunch up. The player can shoot both with one shotgun blast.
- With coordination: Assailant A picks a flank; sets a "claimed flank" fact on a shared Blackboard. Assailant B sees the claim, prices its own claim on that flank higher (claim cost = 10× base), picks the other flank. They split.
Anatomy
Shared Blackboard — BB_SquadCoord
LeftFlankClaimedByActor*- Decay
- 3s if not refreshed
RightFlankClaimedByActor*- Decay
- 3s if not refreshed
Per-assailant schema
LeftFlankAvailableBool (latched)- Source
- claim == null OR claim == self
RightFlankAvailableBool (latched)- Source
- claim == null OR claim == self
OnLeftFlankBool- Source
- Distance-derived
OnRightFlankBool- Source
- Distance-derived
Goals and Actions
DA_Goal_AttackFromLeftIntentGoal- Priority
- 1.0
- Precondition
- LeftFlankAvailable
DA_Goal_AttackFromRightIntentGoal- Priority
- 1.0
- Precondition
- RightFlankAvailable
ClaimLeftFlankIntentAction- Effect
- Sets shared BB fact
ClaimRightFlankIntentAction- Effect
- Sets shared BB fact
MoveToLeftFlankIntentAction- Precondition
- LeftFlankAvailable
MoveToRightFlankIntentAction- Precondition
- RightFlankAvailable
AttackFromCurrentPositionIntentAction- Precondition
- OnLeftFlank OR OnRightFlank
Each assailant's plan looks like: ClaimLeft → MoveToLeft → Attack (or symmetric for Right).
How coordination emerges
ClaimLeftFlank → MoveToLeftFlank → AttackFromCurrentPosition.ClaimLeftFlank), writing to the shared BB. The BB write notifies all listeners — including Assailant B's component (this is a replan-triggering fact on B's schema).LeftFlankAvailable = false. Picks the Right flank goal. Plan: ClaimRightFlank → MoveToRightFlank → AttackFromCurrentPosition.Both planners stay completely independent. No multi-agent solver, no joint plan search, no central controller. Just shared state.
Why this example is here
Three lessons:
- Coordination doesn't require a coordinator. Shared observable state
- per-agent replanning produces emergent coordination. This is how most published GOAP-based multi-agent work has shipped (Boeda 2023 at Square Enix is the most recent AAA writeup — see anti-flap references).
- Claim-decay timers prevent deadlocks. If Assailant A is killed mid-move, its claim must expire so Assailant B can use the flank. A 3-second decay timer with refresh-on-tick handles this.
- The planner layer stays simple. Adding a third assailant is one more pawn with the same archetype, not a new planner mode. Per-unit planning scales linearly; multi-agent planners don't.
Acceptance test
Spawn2 assailants + 1 targetBoth assailants close to target.
+1 replan tickBoth replanAfter 1 second, one assailant is moving Left, the other Right. They never both pick the same side.
Kill LeftSurvivor stays committedAfter 3s, Right assailant's component sees LeftFlankAvailable=true again — but stays committed to its current plan (already moving Right).
Spawn 3rdPicks uncontested flankDefaults to one with a 'support' cost-shaping when both are claimed.
What this example does NOT do
This is basic coordination, not multi-agent planning. Intent Forge doesn't ship:
- Joint plan search across N agents
- Centralised resource allocation (target assignment, ammo balance)
- Strategic-layer planning (HTN-style mission decomposition)
If your project needs any of those, this example is the foundation to build on — but the strategic layer is custom code on top.