Battalion Orchestration (Many Agents, One Runtime)

When several agents should collaborate on one task — rather than serve independent requests — use a Battalion. It runs many Paladins in a single tokio runtime with a coordination pattern built in, so you express the relationship between agents instead of hand-rolling the concurrency.

The example below is compiled code pulled from the paladin-doc-examples crate via mdBook {{#include}}, so it matches the current API.

When to choose it

  • Choose it when the agents form a workflow: a pipeline, a fan-out/fan-in, a DAG, or a lead delegating to specialists. The Battalion owns ordering, concurrency limits, and error strategy for you.
  • Look elsewhere when the agents are independent request handlers — a plain agent registry (optionally behind an HTTP host) fits better than an orchestration pattern.

This is still a single-process topology — it composes naturally with the others: a worker or an HTTP host can run a Battalion as the unit of work it executes.

Example: parallel agents (Phalanx)

A Phalanx fans the same input out to several Paladins concurrently and aggregates the results — the most direct "many agents, one runtime" pattern. Note the with_max_concurrency cap and the BattalionConfig:

#![allow(unused)]
fn main() {
use paladin_battalion::phalanx_service::PhalanxExecutionService;
use paladin_core::platform::container::battalion::phalanx::{AggregationStrategy, Phalanx};

/// Fan the same input out to several Paladins concurrently, then aggregate.
pub async fn run_phalanx() -> Result<(), Box<dyn std::error::Error>> {
    let paladin_port = mock_paladin_port();
    let security = create_paladin("SecurityAuditor");
    let perf = create_paladin("PerformanceAnalyst");
    let style = create_paladin("StyleChecker");

    let phalanx = Phalanx::new(vec![security, perf, style], BattalionConfig::default())?
        .with_aggregation(AggregationStrategy::CollectAll)
        .with_max_concurrency(4); // cap concurrent Paladins

    let service = PhalanxExecutionService::new(paladin_port);
    let result = service
        .execute(&phalanx, "Review this Rust module...")
        .await?;

    println!("Aggregated: {}", result.final_output);
    Ok(())
}
}

Picking a pattern

Your agents should…PatternService type
Run in a fixed order, each feeding the nextFormation (sequential)FormationExecutionService
Run together on the same input, then aggregatePhalanx (parallel)PhalanxExecutionService
Follow explicit dependencies / branchesCampaign (DAG)CampaignExecutionService
Have a lead delegate to specialistsChain of CommandChainOfCommandExecutionService
Use a pattern chosen per-requestCommander (auto-route)CommanderBuilder

The full guides cover every pattern with a worked, compiled example, plus Conclave, Council, Grove, and the Maneuver flow DSL:


← Back to Choosing a topology