@elata-biosciences/agentforge
v0.1.0
Published
Type-safe agent-based simulation framework for Foundry/EVM protocols
Maintainers
Readme
AgentForge is an agent-based simulation framework for Foundry/EVM protocols. Define autonomous agents, run them against your smart contracts, and validate economic invariants with deterministic, reproducible results.
Traditional testing validates individual functions. Agent-based modeling validates emergent system behavior—what happens when hundreds of users interact simultaneously? Does your AMM stay solvent under volatility? How do rational actors exploit edge cases?
Installation
pnpm add @elata-biosciences/agentforgeRequirements: Node.js 18+ and Foundry with Anvil for EVM simulations.
Quick Start
# Initialize project structure
npx agentforge init
# Run built-in toy scenario to verify setup
npx agentforge run --toy
# Check environment
npx agentforge doctorWriting a Scenario
import { defineScenario } from '@elata-biosciences/agentforge';
import { ToyPack, RandomTraderAgent, MomentumAgent } from '@elata-biosciences/agentforge/toy';
export default defineScenario({
name: 'market-stress',
seed: 42,
ticks: 100,
tickSeconds: 3600,
pack: new ToyPack({
assets: [{ name: 'TOKEN', initialPrice: 100, volatility: 0.05 }],
initialCash: 10000,
}),
agents: [
{ type: RandomTraderAgent, count: 10 },
{ type: MomentumAgent, count: 5, params: { threshold: 0.02 } },
],
assertions: [
{ type: 'gt', metric: 'totalVolume', value: 0 },
{ type: 'gte', metric: 'successRate', value: 0.9 },
],
});Run it:
npx agentforge run sim/scenarios/market-stress.tsWriting an Agent
Extend BaseAgent and implement step():
import { BaseAgent, type Action, type TickContext } from '@elata-biosciences/agentforge';
export class MyAgent extends BaseAgent {
async step(ctx: TickContext): Promise<Action | null> {
// 30% chance to buy each tick
if (ctx.rng.chance(0.3)) {
return {
id: this.generateActionId('buy', ctx.tick),
name: 'buy',
params: { amount: ctx.rng.nextInt(1, 100), asset: 'TOKEN' },
};
}
return null; // Skip this tick
}
}Agents have access to:
ctx.rng— Deterministic random number generatorthis.remember()/this.recall()— Persist state across ticksthis.setCooldown()/this.isOnCooldown()— Rate-limit actionsthis.getParam()— Access scenario-defined parameters
CLI
agentforge init [path] # Initialize simulation folder
agentforge run <scenario> # Execute a scenario
agentforge run --toy # Run built-in demo
agentforge doctor # Check dependencies
agentforge types # Generate types from Foundry artifactsOptions for run:
--seed <n> # Override random seed
--ticks <n> # Override tick count
--out <dir> # Output directory
--ci # CI mode (no colors)
--verbose # Verbose loggingOutput
Each run produces:
results/<scenario>-<timestamp>/
├── summary.json # Metadata, metrics, assertion results
├── metrics.csv # Time-series data
├── actions.ndjson # Action log
└── config_resolved.json # Resolved configurationCore Concepts
Scenarios define simulation parameters: seed, duration, agents, and assertions.
Packs are protocol adapters that set up blockchain state and handle contract interactions.
Agents are autonomous actors that observe state and decide actions each tick.
Determinism: Same seed + same scenario = identical results. All randomness derives from seeded RNG.
Examples
See examples/ for working code:
basic-simulation/— Minimal setupcustom-agent/— Memory, cooldowns, custom logicassertions/— Validation and failure handlingmetrics-tracking/— CSV analysis
CI Integration
- name: Run simulations
run: npx agentforge run sim/scenarios/stress.ts --ci --seed 42Assertions fail CI on invariant violations.
API
// Core
import { defineScenario, BaseAgent, SimulationEngine } from '@elata-biosciences/agentforge';
import type { Scenario, Action, TickContext, Pack } from '@elata-biosciences/agentforge';
// Adapters
import { spawnAnvil, createViemClient } from '@elata-biosciences/agentforge/adapters';
// Toy simulation
import { ToyPack, RandomTraderAgent, MomentumAgent } from '@elata-biosciences/agentforge/toy';Contributing
See CONTRIBUTING.md.
License
MIT
