Skip to main content
Foundation is a multi-agent economic simulation framework. Every simulation is an instance of a Scenario class—a subclass of BaseEnvironment—that composes Components, Agents, and Entities into a runnable environment with a standard Gym-style API.

Core building blocks

Scenarios

Subclasses of BaseEnvironment that define passive world dynamics, observations, and reward functions.

Components

Pluggable modules that add action spaces and active dynamics on top of a scenario.

Agents

Stateful actors—mobile agents and a social planner—that act inside the world.

Entities

Resources, Landmarks, and Endogenous variables that make up the world state.

Architecture overview

At the top sits BaseEnvironment (base_env.py). Concrete scenario classes inherit from it and are registered in scenario_registry. Each scenario instantiates:
  • A World object (the 2-D map plus agent objects)
  • One BasicPlanner and n_agents BasicMobileAgent instances
  • One component object per entry in the components constructor argument
All four kinds of building blocks—Scenarios, Components, Agents, and Entities—are registered via the same Registry utility and looked up by name at construction time.

Episode data flow

Each episode follows a fixed sequence:
Observations are assembled from two sources: generate_observations() on the scenario, and generate_observations() on each component. The environment merges them and optionally flattens them into a single "flat" numpy array per agent.

Registry-based plugin system

Every building block registers itself with a @registry.add decorator. The Registry class (base/registrar.py) stores a {name.lower(): class} lookup and enforces that every entry is a subclass of the corresponding base class.
The same pattern applies to scenarios, agents, and entities:
Registered names must be unique within each registry and must not contain a . character. Look up a class by name with registry.get(name), and check existence with registry.has(name).

Constructing an environment

The components argument is an ordered list of ("ComponentName", {kwargs}) tuples. The order matters: component_step() and generate_observations() are called in the listed order every timestep.
Coin and Labor are always included in every environment. Coin is added to resources automatically; Labor is added to endogenous variables automatically.