castellan evolve
Evolve harness topology from episode logs. Optional Python GEPA hook; drift gate rejects incompatible mutations.
Usage
castellan evolve [--episodes 10] [--workspace .castellan/episodes] [--hook rust|seed-only] [--summarize]
castellan evolve --plan
castellan evolve --dry-run
castellan evolve --apply-proposal <UUID>
Key flags
| Flag | Default | Notes |
|---|---|---|
--episodes | 10 | Generations to run |
--workspace | .castellan/episodes | Episode JSON corpus directory |
--hook | rust | Proposer hook (seed-only for fixture tests) |
--summarize | off | Write .castellan/episode_summary.json without evolving |
--plan | off | Read-only analysis: emit an evolution plan JSON, zero writes |
--dry-run | off | Persist proposals to .castellan/proposals/, no archive writes |
--apply-proposal | — | Resolve one persisted proposal (drift gate re-checked) |
--summarize compacts the corpus for the proposer (DRY with substrate heatmap). Drift-incompatible candidates are rejected and logged.
Plan vs dry-run vs apply
| Mode | Reads corpus | Writes proposals | Writes archive |
|---|---|---|---|
--plan | yes | no | no |
--dry-run | yes | yes | no |
--apply-proposal | yes | resolves one | on accept |
Use --plan for a pre-mutation analysis turn (incumbent, proposed coordination, pressure summary, drift preview, fitness estimate), then --dry-run + --apply-proposal (or the MCP castellan_propose_mutation / castellan_resolve_mutation pair) for the gated two-phase apply.
Recipes
Standard evolve from local episodes:
castellan run --goal "reach target" --plugin gridworld
castellan evolve --episodes 10 --workspace .castellan/episodes
Summarize only (no mutation):
castellan evolve --summarize --workspace .castellan/episodes
Seed archive then run:
castellan evolve --episodes 10
castellan run --goal "reach target" --plugin gridworld --seed-archive