One object

A market, a network, and a democracy are the same kind of object

The problem: markets, information networks, and democratic institutions are studied by different fields, in formalisms that do not compose — so nobody can run them against each other. The Collective Intelligence Library starts from the observation that as graphs they are one kind of object: message passing over a relation, differing only in what flows and how nodes update.

Everything on this page is built from artifacts the engine exported — every diagram and every curve below is something the engine actually derived.

A market, a network, and a democracy are the same kind of object — engine artifactState 01 / 02
j1ψj2ψj3ψiγi′t+1trust (row-stochastic)
relation W
trust (row-stochastic)
ψ — what flows
Wᵢⱼ · xⱼ
⨁ — how arrivals combine
sum
γ — what the receiver does
identity (a contraction)

Seven literatures, one equation (whitepaper Table 3 — six shown here). The traditions differ only in how they fill the three slots and which relation they read. The picture is a schematic of one step; pick a tradition and the fills change.

One object
01 / 02The equation

Nearly every dynamic process has one shape

Each unit forms a message per neighbour, arriving messages combine by an order-independent operation, and the unit updates — that is the whole picture. Opinion pooling, voting, market clearing, production networks, contagion, graph neural networks: each tradition is one way of filling the three colored slots. Pick one and watch the same picture refill.

02 / 02One state

All of it lives in one immutable state

Committing to one representation needs one state type: a population, typed nodes, named per-agent arrays, named relation layers, world-level values. A domain is a layer of this one object, not a module — which is why coupling an economy to a polity is an ordinary step, never new machinery. These are the actual fields of the governed commons you will follow down this page.

One step

Rules change the state — and say what they touch

The problem: if anyone can write a rule that changes the world, how does anyone else know what it affects? The library’s answer is that an institution is a pure function from state to state that declares the fields it reads and writes. The declaration is the entire interface — no base class, no registration protocol, nothing else to know.

Rules change the state — and say what they touch — engine artifactState 01 / 02

@transformharvest

readscumulative_harvestdelegate_actionpolicy_targetresource_levelrng_key
writescumulative_harvestlast_harvestlast_rewardresource_levelrng_key

@transformregrow

readsresource_level
writesresource_level

The declaration is the whole interface: no mechanism references, calls, or knows another — they meet in the state, through these names.

the code — dynamics.py
def make_harvest(cfg: GovernedCommonsConfig):
"""Compliant delegates take ``min(desired, policy_target)``; Bernoulli defectors take
``desired``. Everyone scales down proportionally if total demand exceeds the stock.
``last_reward := last_harvest`` (a later sanction mechanism may overwrite it)."""
N = cfg.n_households
 
@transform(reads=[delegate_action, policy_target, resource_level,
cumulative_harvest, rng_key],
writes=[last_harvest, last_reward, cumulative_harvest,
resource_level, rng_key])
def harvest(state: GraphState) -> GraphState:
state, key = _split_key(state)
desired = state.node_attrs["delegate_action"]
target = state.global_attrs["policy_target"]
defect = jr.bernoulli(key, p=cfg.defect_prob, shape=(N,))
taken = jnp.where(defect, desired, jnp.minimum(desired, target))
 
R = state.global_attrs["resource_level"]
total = jnp.sum(taken)
scale = jnp.where(total > R, R / (total + 1e-8), 1.0)
actual = taken * scale
 
state = state.update_node_attrs("last_harvest", actual)
state = state.update_node_attrs("last_reward", actual)
state = state.update_node_attrs(
"cumulative_harvest", state.node_attrs["cumulative_harvest"] + actual)
return state.update_global_attr(
"resource_level", jnp.maximum(R - jnp.sum(actual), 0.0))
return harvest
One step
01 / 02The declaration

An institution is a function with declared effects

Two steps of the governed commons: households harvest through delegates, and the stock regrows. The read/write chips are the declarations the engine consumes — open the code panel to see them on the real transform.

02 / 02Timing as data

Institutions do not share a clock

The problem: markets clear continuously, elections are periodic, regulations switch on at a date — one loop cannot hard-code all of that. So the engine runs every environment on background ticks, and each transform is placed on them by three numbers: how often (cadence), where in the cycle (phase_offset), and from when (onset). The timeline shows the real pipeline’s rows; drag the vote’s dials and watch its ScheduleSpec — the schedule is data you can sweep, not code you rewrite.

The compiler

What order should things run in?

The problem: you add a vote, a stranger adds sanctions, and both touch the same world — who runs first, and does either break the other? Most frameworks answer socially: read both codebases and hope. Here nobody writes the order down. Because every transform declares what it reads and writes, the order is computed from the type definitions — resource ordering over the declared effects — so every environment gets one consistent within-tick schedule, derived, not authored.

What order should things run in? — engine artifactState 01 / 05
batch 0harvest
batch 1regrow
  • harvestregrowRAWWARWAW

Transforms declare what they read and write; the compiler derives who must wait for whom. Two transforms with no shared field run in the same batch — in parallel.

The compiler
01 / 05Two steps

Shared fields become ordering

Harvest and regrowth both touch the resource stock, so the compiler runs them in sequence. The dependency is read off the declarations — read-after-write, write-after-write — never written by hand.

02 / 05Add a vote

A new institution slots in without touching the others

A quota vote reads the households’ votes and writes next round’s harvest target. It shares no field with regrowth, so the two run in the same batch, in parallel. Adding an institution never means editing another one.

03 / 05Add sanctions

The compiler serializes what actually conflicts

Graduated sanctions read the target the vote wrote, so they wait for the vote’s batch. Toggle any subset of the four transforms above — every ordering you can produce was derived by the engine’s compiler and shipped as a lookup table.

04 / 05The system view

The same declarations draw the system

Reads and writes also make every pipeline a communication graph nobody hand-drew: state fields on the left, transforms on the right, reads flowing right and writes flowing back. This is the undefended commons.

05 / 05Toggle a mechanism

Switching on governance adds its nodes

Under the defended condition the vote and sanction transforms appear, wired to exactly the fields their declarations name. Attaching them is data, not surgery — a benchmark condition is a list of (mechanism, config, schedule) triples, as the code panel shows.

One arrow

Putting institutions together is function composition

The problem: every framework promises that its pieces compose, and in most of them composition is a social fact — things work together because their authors were careful. The library takes the answer applied category theory suggests: make every institution the same kind of arrow, from state to state, and combining institutions stops being a hope and becomes an operation with laws.

The point of the laws is leverage — complexity from simplicity. Because composites are arrows again, simple steps build arbitrarily large worlds, and the twentieth institution is added exactly the way the second was: the integration work does not grow with the size of the build. The diagrams below are drawn from the same exported declarations the compiler consumes, and each one states one checkable fact about how the engine combines functions.

Putting institutions together is function composition — engine artifactState 01 / 04
SSSharvestregrowregrowharvest

GraphState → GraphState — the type of every transform and of every composite

Two transforms of the governed commons and their composite. Arrows out of and into the same object compose, composition is associative, and doing nothing is the identity arrow — the entire algebra a pipeline needs.

the code — dynamics.py
def make_harvest(cfg: GovernedCommonsConfig):
"""Compliant delegates take ``min(desired, policy_target)``; Bernoulli defectors take
``desired``. Everyone scales down proportionally if total demand exceeds the stock.
``last_reward := last_harvest`` (a later sanction mechanism may overwrite it)."""
N = cfg.n_households
 
@transform(reads=[delegate_action, policy_target, resource_level,
cumulative_harvest, rng_key],
writes=[last_harvest, last_reward, cumulative_harvest,
resource_level, rng_key])
def harvest(state: GraphState) -> GraphState:
state, key = _split_key(state)
desired = state.node_attrs["delegate_action"]
target = state.global_attrs["policy_target"]
defect = jr.bernoulli(key, p=cfg.defect_prob, shape=(N,))
taken = jnp.where(defect, desired, jnp.minimum(desired, target))
 
R = state.global_attrs["resource_level"]
total = jnp.sum(taken)
scale = jnp.where(total > R, R / (total + 1e-8), 1.0)
actual = taken * scale
 
state = state.update_node_attrs("last_harvest", actual)
state = state.update_node_attrs("last_reward", actual)
state = state.update_node_attrs(
"cumulative_harvest", state.node_attrs["cumulative_harvest"] + actual)
return state.update_global_attr(
"resource_level", jnp.maximum(R - jnp.sum(actual), 0.0))
return harvest
One arrow
01 / 04One type

Every institution is an arrow from state to state

One object, the state; arrows, the transforms — each a pure function from GraphState to GraphState. Arrows out of and into the same object compose, and the composite has the same type again, so a pipeline of any length is just another arrow. This closure is why the engine treats a single harvest rule and a whole governed economy uniformly: both are one arrow.

02 / 04Refined types

Declared effects refine the type of each arrow

State to state alone says too little — any step could depend on anything, and nothing about a composite could ever be derived. The reads and writes declarations sharpen the type: harvest factors through the slice of the state it may see and the slice it may replace, acting as the identity everywhere else. The factorisation, not the function body, is the interface the compiler works with.

03 / 04Commutation

Disjoint effects make the square commute

Two arrows whose declared effects share no field give the same composite in either order. The square commutes, the ordering question dissolves, and the pair collapses into one parallel arrow — regrowth and the quota vote are that pair in this pipeline. Every parallel batch the compiler section showed is an instance of this square, proved from the declarations rather than asserted by an author.

04 / 04Time

One tick is a composite; a run is its iterate

Reassemble the batches and one tick of the world is a single composite arrow — sanctions after the parallel pair after harvest, exactly as the compiler factorised it. A run applies that arrow T times, and a scheduled transform substitutes the identity on ticks where it does not fire, so timing changes which factors appear without touching the algebra. Sweeping seeds is vmap lifting the same arrow to a batch of states while preserving composition — the categorical reading of why sweeps need no new code.

One matrix

Any graph is a matrix

The problem: pictures of graphs do not compute. To run and to measure these worlds at scale, the engine stores every relation the same way — a matrix over the population. The graph below is real: the friendship layer of the library’s cultural-contagion model, exported with its spectrum.

Any graph is a matrix — engine artifactState 01 / 03
the graph
the same object as a matrix

value_contagion’s friendship layer, N=40, seed 0, engine-exported. Hover a cell: row i is agent i’s incoming mail.

One matrix
01 / 03Two views

The node-link picture and the matrix are the same object

Every relation layer is an N-by-N array: entry (i, j) is the tie from j to i. Hover the matrix and watch the graph — row i is agent i’s incoming mail. There is no second data structure; the picture on the left is a drawing of the array on the right.

02 / 03One multiply

One step of the world is one matrix multiply

This is what the representation buys. Aggregating every agent’s neighbours — the ⨁ of the opening equation — is W times x, one line of linear algebra for any attribute shape. Row-normalise W and the step averages, so opinions pool toward consensus; leave it raw and the step accumulates, so resources compound; the diagonal is memory. Institutional dynamics become properties of matrices.

03 / 03Sorted

Sort the rows by one eigenvector and structure appears

Same matrix, rows and columns reordered by the Laplacian’s second eigenvector. Ties pull toward the diagonal and the graph’s hidden community structure becomes visible blocks. That eigenvector is doing real work — which is the door to the last section.

Reading structure

Measuring the system without running it

The problem: at forty agents you can look at a picture; at forty thousand you cannot. Spectral graph theory is the mathematics that still reads a system after it has grown too large to draw — and because relations are matrices, its toolkit applies directly. It pays twice: readouts of structure before any outcome unfolds, and a supply of new metrics, since every spectral quantity is a candidate instrument for collective structure. The ones below were computed by the engine for the graph you just saw.

Measuring the system without running it — engine artifactState 01 / 02
013.2λ₂ = 1.2444 — the spectral gap

Every bar is one eigenvalue of L = D − W for the friendship graph above. λ₁ = 0 always; the gap to λ₂ sets how fast local perturbations become global patterns under diffusion — the larger the gap, the faster this graph turns local noise into shared state.

Reading structure
01 / 02The spectrum

The Laplacian spectrum is the system’s X-ray

The eigenvalues of L = D − W summarise how the graph carries signals. The gap between the first two sets how fast local perturbations become global patterns: a large gap means the collective homogenises quickly, a small one means communities hold out. One number, no simulation required.

02 / 02The fault line

The Fiedler vector finds the fault line

The second eigenvector cuts the graph at its weakest links — the system’s primary fault line. The library’s capture detector asks whether that fault line aligns with the human/AI boundary. On this graph, at its default mixing, it does not — and that score is exactly what would move first if it started to. Spectral gap, fault-line alignment, mediation shares: these are the readouts the observability layer will put behind live dashboards next.

Where this goes

The views this opens

A fault-line monitor

The Fiedler split of the influence graph, recomputed as the world runs, with one line tracking its alignment to the human/AI boundary. Flat near zero means the graph’s divisions are not the species divide; a climb is capture forming — visible in the structure long before any outcome shows it.

A speed-of-consensus dial

The spectral gap computed separately over the human-only and AI-only subgraphs, shown as a ratio. Whichever side homogenises faster sets the attractor the whole system drifts toward — a single dial for who is winning the coordination race.

A bridge map

Betweenness concentrated at the nodes that sit between the types — who mediates the flow between human and AI communities. Drawn as the graph above with the brokers enlarged: when a handful of nodes carry most cross-boundary paths, influence over the interface has concentrated there.

An influence ticker

A causal influence reading on a schedule inside a live simulation: shift what every member asks for, replay the world under identical randomness, and plot whether outcomes still move. A healthy line holds level; gradual disempowerment is that line sagging while every outcome metric still looks fine.

One of these — the fault-line score — runs in the engine today and produced the number above. The others are designed metrics of the same family, waiting on the observability layer that will stream them from live runs.

Going deeper

The whitepaper

Everything this page showed — the one equation, the single state, declared effects, the derived order, the categorical algebra, the matrix view and its spectrum — is developed in full in the whitepaper, The Collective Intelligence Library: Composable Mechanism Simulation and Measurement on Graphs, an alpha-release working paper. It carries the assumptions behind each model and the measurement discipline the engine ships with.

Read the whitepaper — PDF

Every figure on this page renders artifacts exported by the engine — collective-intelligence-library 0.1.0 @ b3837e2, fixture set 2026-08-07. Nothing is simulated in the browser.