EvoNet
An agent-based simulation of an arms race between self-replicating spreading agents and a defender, across three network topologies. 330 reproducible runs and a paper-style write-up.

EvoNet asks what evolves when a population of spreading agents is hunted by a defender, and how much the shape of the network matters. It’s deliberately abstract: an agent is a 16-float parameter vector, not code, and detection is a probability, not a scanner. That makes topology, defender memory and perturbation rate clean independent variables, and every run is exactly reproducible from a config and a seed.
The model
Six of the sixteen parameters do something: spread aggressiveness, stealth, self-perturbation rate, mixing rate, a preference for high-degree neighbours, and payload diversity (variance on spread success). The rest are inert and drift. The perturbation rate is itself a parameter, so how fast agents change is also under selection.
Each tick: agents try to spread to neighbours, co-located agents may mix parameters, the defender removes some, background removal takes a few more, and overfull nodes are culled. The defender is either static (detection falls with stealth) or adaptive, keeping a decaying histogram of the stealth values it has seen and punishing whatever is currently common.
The main experiment is 3 topologies (Erdős–Rényi, Barabási–Albert, Watts–Strogatz) × 2 defenders × mixing on/off, 10 replicates of 2000 ticks each.

What came out
- Stealth rises with detection pressure: 0.08 with no defender, 0.44 static, 0.64 adaptive. The adaptive defender keeps the population spread out instead of converging on one strategy.
- Topology changes how big a population survives, not which strategy wins (p = 0.94 for stealth). The scale-free graph sustains the smallest population, the reverse of the classic spectral-threshold ordering.
- The apparent benefit of parameter mixing was an artefact of the fitness proxy inside the mixing operator. With a neutral replacement rule it disappears.
- A multiplicative signature term leaves agents at maximum stealth permanently undetectable; an additive one closes that gap.
Running it
pip install -r requirements.txt
python cli.py experiment configs/default.json --experiment_name main --figures
About ten minutes on four cores. The full write-up is in paper/evonet_paper.md.