Skip to content

systemshift/AgentStan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AgentStan

AI-native agent-based modeling framework.

Simulate. Test. Analyze. Narrate.

pip install agentstan

Quick Start

A 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.

Rule language in one minute

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"}]}
]

Packs — save, share, export your work

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 entry

A 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.

Python behaviors (escape hatch)

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.

The STAN Framework

Simulate — Run agent-based models

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()

Test — Batch runs and parameter sweeps

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}")

Analyze — Understand what happened

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}, ...}}

Narrate — AI explains the results

# 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")

CLI

# 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 300

Architecture

agentstan/
  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)

DeFi stress testing

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.

License

BSD 3-Clause

About

Agent-Based Modeling Library for LLMs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages