AI-native agent-based modeling framework.
Simulate. Test. Analyze. Narrate.
pip install agentstanA model is pure JSON — environment, agents, and behaviors are all data. No code in the spec means it can be stored, diffed, generated by an LLM, validated, and executed by any engine that implements the spec.
from agentstan import Simulation
spec = {
"seed": 42, # same spec + same seed = same results, every time
"environment": {"type": "grid_2d", "dimensions": {"width": 40, "height": 40, "topology": "torus"}},
"agent_types": {
"rabbit": {
"initial_count": 80,
"initial_state": {"energy": 25, "perception_radius": 5},
"behavior": {
"rules": [
# Graze when hungry
{"when": {"<": ["$energy", 20]},
"do": [{"type": "modify_state", "attribute": "energy", "delta": 2}]},
# Flee the nearest wolf
{"when": {">": [{"count": {"type": "wolf"}}, 0]},
"do": [{"type": "move_away", "from": {"nearest": {"type": "wolf"}}}]},
# Otherwise wander
{"when": {"==": [{"count": {"type": "wolf"}}, 0]},
"do": [{"type": "move", "direction": [{"choice": [-1, 0, 1]}, {"choice": [-1, 0, 1]}]}]},
# Reproduce when well-fed
{"when": {">": ["$energy", 30]}, "prob": 0.08,
"do": [{"type": "reproduce", "energy_cost": 15}]},
# Metabolism and starvation
{"do": [{"type": "modify_state", "attribute": "energy", "delta": -0.8}]},
{"when": {"<=": ["$energy", 0]}, "do": [{"type": "die", "cause": "starvation"}]},
]
}
}
}
}
sim = Simulation(spec)
results = sim.run(200)
print(results["summary"]["final_counts"])See examples/predator_prey_rules.py for the full two-species model, and
agentstan/core/rules.py for the complete expression/action reference.
Each rule is {"when": <condition>, "prob": <chance>, "do": [<actions>]} —
every rule whose condition holds fires, in order. Expressions are single-key
dicts: comparisons (<, >=, == …), arithmetic (+, * …), logic
(and, or, not), randomness (random, choice, uniform), and
neighbor queries (count, nearest_distance). "$energy" reads the agent's
own state; selectors like {"nearest": {"type": "wolf"}} pick a target agent
for move_toward, move_away, and interact.
The kernel is domain-blind: interactions are generic effects
(kill_target, transfer, self_delta, target_delta), reproduction
costs any attribute you choose, and world laws are spec data too — e.g.
death at zero energy is a top-level "global_rules" entry, not engine code:
"global_rules": [
{"when": {"<=": ["$energy", 0]}, "do": [{"type": "die", "cause": "energy_depleted"}]}
]A pack is a single JSON file bundling models (runnable specs) and named scenarios (parameter variations) plus metadata. Packs are 100% data — they can be stored anywhere, shared, versioned, and run by anyone with the library:
from agentstan.pack import load
pack = load("goblin-economy.pack.json")
print(pack.models, pack.scenarios) # ['base'] ['gold-rush', 'crash']
results = pack.run("gold-rush") # resolves overrides, seeds, runs
pack.validate(deep=True) # full engine validation of every entryA scenario is just dot-path overrides on a model:
"scenarios": {
"gold-rush": {"model": "base", "steps": 500, "seed": 7,
"overrides": {"agent_types.miner.initial_count": 40}}
}The format is versioned (schema_version), so packs you export today keep
loading tomorrow.
For local power users, an agent type may instead define behavior_code — a
Python function as a string (see examples/predator_prey.py). This is not
recommended for anything that stores or transmits specs: it is not
sandbox-safe and not portable. Prefer rules.
from agentstan import Simulation, StagedScheduler, DataCollector
sim = Simulation(spec, scheduler=StagedScheduler(["prey", "predator"]))
collector = DataCollector(
model_metrics={"avg_energy": lambda s: sum(a["energy"] for a in s.agent_manager.get_living_agents()) / max(s.agent_manager.get_total_count(), 1)},
)
sim.add_collector(collector)
results = sim.run(200)
time_series = collector.get_model_data()from agentstan.experiment import batch_run, sweep
# Run 50 times to get statistical confidence (seed makes the batch reproducible)
results = batch_run(spec, n_runs=50, steps=200, seed=1000)
# Sweep a parameter
results = sweep(spec, param="agent_types.wolf.initial_count", values=range(5, 50, 5), n_runs=10)
for val, runs in results.items():
avg = sum(r["summary"]["final_counts"].get("wolf", 0) for r in runs) / len(runs)
print(f"wolves={val}: avg final = {avg:.1f}")from agentstan.analysis import analyze_population, analyze_events
pop_report = analyze_population(results)
# {'agent_types': {'rabbit': {'stability': 'oscillating', 'period': 34, ...}}}
event_report = analyze_events(results)
# {'deaths': {'by_cause': {'starvation': 42, 'predation': 18}, ...}}# pip install agentstan[ai]
from agentstan.ai import generate, interpret, validate
# Generate a model from natural language
spec = generate("simulate wolves hunting rabbits in a forest")
# Run it
sim = Simulation(spec)
results = sim.run(200)
# AI explains what happened
explanation = interpret(results)
# "Rabbits peaked at step 34 then crashed due to overgrazing..."
# Validate the model matches the description
issues = validate(spec, "wolves should hunt rabbits")# Run from spec file
agentstan --from-spec ecosystem.json --steps 200
# Batch run
agentstan --from-spec ecosystem.json --batch 50 --analyze
# Generate from natural language (requires agentstan[ai])
agentstan "simulate ants foraging for food" --steps 300agentstan/
core/ # Simulation engine, agents, environments, schedulers
experiment/ # Batch runs, parameter sweeps
analysis/ # Population dynamics, event analysis
ai/ # LLM-powered generation, interpretation, validation
defi/ # DeFi lending stress-testing (see below)
agentstan.defi is a self-serve simulation lab for DeFi lending protocols —
stress-test your protocol before it breaks. Describe a market in plain
language, run crash / depeg / whale-panic scenarios against it, sweep parameters
to find the safe frontier, and export a governance-ready report.
from agentstan.defi import author_config, LendingMarket
cfg = author_config("USDC market, 75% max LTV, stress a 40% ETH crash with a slow oracle")
print(LendingMarket(cfg).run(120)["summary"]["bad_debt"])Deterministic protocol mechanics (interest, oracle, liquidation, slippage) +
constrained LLM behavioral agents, validated against real events (MakerDAO Black
Thursday, the Aave CRV squeeze). See agentstan/defi/README.md.
BSD 3-Clause