ECS: The software architecture for Agent-Based Models
Building the economy one component after another
The Standard Model of Physics
Any physics aficionado who visits CERN returns with a mug or a T-shirt displaying the Standard Model. The formula is strikingly elegant. Every particle interaction in the universe, minus gravity (one for another day), in just four lines.
That elegance comes from a specific formalism. The Standard Model is built as a Lagrangian: a mathematical object that encodes the dynamics of a system – how its fundamental degrees of freedom evolve and interact over time.
The Lagrangian formalism enables a compositional approach: different terms describe different physical phenomena, and their sum describes (most of) the universe. In this blog post, we will argue that composability, in physics as elsewhere, is a powerful and principled way to tame complexity.
One term after another
A physicist building a model starts by identifying the fundamental degrees of freedom of nature. At the most basic level, these are the four fundamental fields: electron, quark, photon, gluon. What we call particles are excitations of these fields.
Each field is characterized by a set of intrinsic properties: charge, spin, mass, and how it transforms under the theory’s symmetries. The electron field, for instance, carries electric charge -1, spin 1/2, and transforms as a lepton under the gauge symmetries of the Standard Model.
The simplest Lagrangian you can write for a field contains a kinetic term: this describes how the field propagates freely through spacetime without interactions. To make fields interact, you add coupling terms. A coupling between the electron field and the electromagnetic field gives rise to electromagnetism: electrons emit and absorb photons. Each additional term introduces new physical phenomena while preserving the structure already in place.
Now, suppose you want to explore new physics, beyond what is currently known. Physicists working at this frontier do not rewrite their equations from scratch. They write
The existing terms stay exactly as they are. New phenomena are introduced purely by addition.
This works because the Lagrangian formalism is modular. Fields are defined by their intrinsic properties and transformation rules; interactions define how fields can be coupled. Neither defines the other. You can write a new interaction term that couples to an existing field without changing anything about how that field was originally described. Not any term will do, though. Symmetries forbid most of them, and what survives is disciplined by what the theory must conserve.
This is a powerful modeling discipline: separate what exists from the rules that couple it, and grow complexity by addition, one term after another, rather than by rewriting. Can the same principle be applied to modelling the complex dynamics of the economy?
Simulating economic systems
Unlike physical systems, economic systems resist compression in compact equations. Entities are heterogeneous and adaptive: firms change strategy, households update beliefs, and institutions evolve. This is probably why economics will never have a Standard Model in the same sense as physics — the right level of description is not an equation but a procedure. A useful economic simulator therefore needs the same kind of composability physicists get from the Lagrangian formalism, but realized in code rather than equations.
Such a simulator would let you start simple — a basic supply chain, a handful of firms, some consumers — and add economic mechanisms the same way a physicist adds terms to the Lagrangian – one at a time: price formation, inventory constraints, agent learning, regulatory interventions. Each addition should be legible and isolated. You should be able to ask what it changes, run controlled experiments, and eventually calibrate against real data — without the model getting harder to understand, test, or extend as it grows. And as in physics, this composability needs a discipline: modules should respect accounting invariance, so that money is conserved across mechanisms.
So the question becomes: what software architecture provides this kind of composability?
The inheritance problem
The video game industry faced a version of the same problem. Games need to be extensible — players want to mod them, studios want to expand them long after release — and game entities need to be composable. In object-oriented programming (OOP), the natural instinct is to model them with inheritance: a FlyingEnemy extends Enemy, a MagicEnemy extends Enemy, and each works fine in isolation. But when you need a MagicFlyingEnemy, the hierarchy grows combinatorially. Each new capability multiplies the number of classes required.
Economic simulators hit the same wall. A Firm class that handles production is fine until you need firms that also trade across borders, hold inventories, respond to tariffs, and learn from past outcomes. In a research setting, the problem compounds: multiple researchers each want to extend the model with their own mechanisms — one adds credit constraints, another adds learning, a third adds regulatory responses — and their work quickly conflicts.
For game developers, the fix was a different question: not what something is, but what it has and what acts on it. Out went inheritance, in came composition.
The Entity-Component-System (ECS) architecture
That architecture is Entity-Component-System (ECS). Concretely: a flying enemy is just an entity with two components, a Position and a Velocity. Add SpellList as a third and it becomes a magic flying enemy. No new class is needed; the spell system simply starts acting on it as well.
The ECS architecture formalizes this into three concepts.
Entities are identifiers only: no data, no logic — just an integer tag. They are “this particle” or “this firm.”
Components are data only: no methods, no behavior, just plain values attached to an entity — position, velocity, mass, price, inventory level.
Systems are logic only: each system queries for entities carrying a specific set of components and applies some transformation to them. A gravity system finds everything with a Position and a Mass. A pricing system finds everything with an Inventory and a Price. Anything that does not carry the required components is invisible to that system.
This also changes what a simulation is. The world state lives in typed tables of components; behavior is what happens when systems query and transform those tables. In that sense, a simulation becomes more like a sequence of structured data transformations than a choreography of objects calling one another’s methods.
The composability
ECS provides that additive extensibility we were looking for. To introduce a new mechanism, you don’t rewrite the existing codebase: you add new components and new systems.
Here is what this looks like in practice. We simulate 2,000 particles under gravity alone, then rerun the same simulation with one addition: a Charge component on each particle, and an EMSystem that couples charged particles through the electromagnetic force. No existing code is modified — two new definitions, one extra system in the pipeline.
Under gravity alone, all particles attract, and matter collapses into dense clusters. Add charge, and repulsion between like-charged particles prevents full collapse – matter disperses outward. Same initial conditions; the only difference is one extra component and one extra system.
Composability is the headline property, but it is not the only one.
The computational edge
The same separation that delivers composability also delivers a highly performant data layout. ECS stores component data in contiguous, typed arrays: all masses together, all charges together, all positions together. Systems read only the arrays they need. Sequential access over flat arrays is exactly the pattern CPUs handle efficiently, and independent systems over typed arrays parallelise cleanly on GPUs. This is what makes simulation at the scale of millions of agents possible – every firm, household, and bank in an economy, each running its own price formation, inventory, credit, and regulatory rules.
It also matters for scientific computing. Automatic differentiation libraries expect flat, typed arrays — which is exactly what ECS component storage produces. Gradients of simulation outputs with respect to parameters become computable, which opens the door to gradient-based calibration against real data, sensitivity analysis, and hybrid approaches that combine mechanistic models with learned components.
Critically, it means you are not forced to pay for this with a global differentiability constraint. Any system that resists exact differentiation — a firm’s discrete entry-or-exit decision, a complex behavioral rule — can be swapped for a differentiable surrogate that slots into the pipeline as just another system acting on the same components. The rest of the simulation is untouched. Differentiability becomes something you add incrementally, precisely where you need it.
So the architecture gives you three things at once: composable extension, hardware-scale performance, and targeted differentiability. What does it look like when you point it at an economy?
What this means for economic simulations
Here is what the same architecture looks like applied to a simple supply chain. Producers in two countries manufacture goods, each carrying a Production component that determines output and a Price component that adjusts based on supply and demand. An assembler purchases inputs from the cheapest available supplier, regardless of country, and sells finished goods to consumers. Consumer demand responds to price. Four systems drive this: ProductionSystem, PricingSystem, MarketSystem, and AssemblySystem. Together they produce a functioning economy with cross-border trade, price discovery, and demand response.
Now suppose you want to study the effect of a 50% import tariff. You don’t touch any of the four existing systems. You write one new system:
# TariffSystem
for (price, seller, buyer) in query(world, Price, Seller, Buyer)
if seller.region != buyer.region
price.value *= (1 + 0.5)
end
end We run the same supply chain simulation twice: once with free trade, once with the TariffSystem added to the pipeline. No other code changes.
The result is a coherent economic response emerging from a single-system addition. Prices rise on cross-border transactions, making imports more expensive. Suppliers within the importing region become relatively cheaper, so trade shifts domestic as the import ratio drops. Domestic suppliers face less competition, and so let their prices settle higher than under free trade. Consumers buy less in response to higher prices. None of these dynamics were coded; they emerged from one new system interacting with four existing ones through shared components.
Toward the Macrocosm
The analogy to physics is less a metaphor than a shared operating principle. A term in the Lagrangian does not know which particle it acts on: it couples to whatever degrees of freedom satisfy its structure. A system in ECS does not know which entity it acts on: it queries for components. The parallel is architectural: behaviour emerges from independent mechanisms acting on shared state, with every coupling visible in the structure.
This is the architecture on which we build increasingly complex economic simulations. An ECS-structured engine lets us compose supply chain, electricity market, and macroeconomic domains from a shared library of components and systems — mechanisms built for one domain become available in all. Macrocosm is building the economy one component at a time.





