Six Numbers That Run a Room
A negotiation simulator with no opinions: six bounded floats, a delta table, and a decay rule.
Every agent in a negotiation gets reduced to six numbers: trust, leverage, tension, dominance, credibility, and momentum. They are clamped between 0 and 1 (momentum spans -1 to 1), they move only by deterministic deltas, and every turn they decay back toward a baseline. There is no free-form state and no LLM reasoning about who likes whom. Six scalars do the arithmetic underneath the dialogue, and that turns out to be enough.
This post is about the social physics layer of Boardroom Simulator, a multi-agent negotiation engine where AI stakeholders with conflicting incentives debate, form coalitions, escalate, compromise, feel emotions, and execute multi-turn strategy. I walk through what each number does, how it moves, how the whole thing flows from "someone said something" to "someone else wins the floor," and why the architecture looks the way it does.
The problem: why "let the LLM figure it out" fails
The naive way to build this is to stuff the conversation into an LLM's context window and ask it to role-play each stakeholder. That produces fluent dialogue and exactly zero coherence. Three turns in, the CFO is simultaneously furious and conciliatory. Trust, power, and emotion exist only as adjectives the model happens to emit this turn. There is nothing to debug, nothing to replay, nothing to measure.
The core design rule of this project is a clean split:
Language generation is separated from behavioral state evolution.
The LLM writes the words. A deterministic machine owns the world: who trusts whom, who holds leverage, who is about to snap. The LLM never decides that the CFO is angry; it is told the CFO is angry (anger = 0.73, interrupt bias +0.4) and asked to write angry words. That machine is the social physics layer, and the social physics layer is six numbers.
Meet the six numbers
Each agent carries its own SocialPhysics state, a Pydantic model with six bounded fields:

The defaults encode a worldview: a fresh negotiation starts mildly tense (0.3), with modest dominance (0.3), and everyone at neutral trust, credibility, and leverage (0.5). Momentum is the only axis that can go negative, since it tracks a direction.
Two things make these six numbers interesting: how they move, and what happens when they cross thresholds.
How a number moves: the delta pipeline
Every action an agent takes (a statement, question, challenge, compromise, coalition_signal, interrupt, or escalate) has a default delta table. Here it is:

Read the shape of this table and the design philosophy falls out:
Escalation is expensive.
escalatebuys dominance (+0.10) and costs trust (-0.15) and credibility (-0.10).Compromise is restorative. It is the mirror image: +0.10 trust, -0.15 tension, +0.05 credibility, +0.05 momentum. The engine rewards de-escalation.
Challenge is a double-edged knife. It raises tension and dominance but costs trust, leverage, and credibility. Notice the direction: a challenge lowers the speaker's credibility. The target's number does not move. (More on that wrinkle at the end.)
A bare delta is not the final number, though. Two more layers modulate it before it lands:
Personality. An agent's traits (aggressiveness, empathy, stubbornness) scale the deltas. The rule is simple and linear:
normalized = (trait − 50) / 50
delta = base × (1 + normalized × strength)An aggressive agent (say, 80) amplifies the tension from a challenge; an empathetic one amplifies the trust from a compromise. Personality acts as a coefficient on the physics.
2. Archetype. Six behavioral archetypes (Opportunist, Idealist, Diplomat, Pragmatist, Agitator, Guardian) apply multipliers on top. An Agitator's challenge multiplies tension by 1.5 and dominance by 1.4; a Diplomat's compromise multiplies trust by 1.3 and inverts tension by -1.3. A Guardian who challenges pays an extra credibility penalty (× -1.1). The same action, in different hands, lands with very different force.
So the full pipeline for a single number is:
action → default delta → personality modulation → archetype multiplier → clamp to [0,1]Three pure transforms, no LLM, no randomness.
Homeostasis: every number wants to go home
Raw deltas would eventually pin every value at 0 or 1 and the simulation would freeze into a caricature. So after each turn, everything decays toward its baseline at a fixed rate:
value = value + (baseline − value) × 0.05Tension drifts back to 0.3, trust and credibility to 0.5, momentum to 0.0. This is a homeostatic loop: the system resists extreme states. You can spike tension to 0.9 with a brutal escalation, but unless you keep feeding it, it bleeds back toward 0.3 over the next few turns.
This single rule is what keeps long simulations from spiraling out of control. It also makes escalation a choice you have to keep making, since nothing ratchets in one direction on its own.
Thresholds: when a number stops being a number
The moment the numbers matter is when one crosses a threshold. threshold_triggers() is a pure function mapping each extreme to a named event:

Each trigger rewrites the agent's goals through a separate GoalEvolution component, which maps triggers to new objectives:

Each goal spawns a multi-turn plan with auto-generated subgoals ("acknowledge concerns," "offer concessions," "restate position with evidence"), and the plan summary is injected into the agent's system prompt every turn. So when a number crosses a line, the agent's objectives for the next several turns change. The numbers form a feedback loop that reaches from the physics all the way into strategy.
Feeding "who speaks next": the hybrid urgency
The last thing the numbers drive is also the most visible: floor control. In a room of agents, someone has to speak next, and the six numbers decide the odds.
The deterministic part of a bid is built directly from the physics:
base = urgency × 50 + 50
if tension > 0.7: base += 15 # the room is hot — jump in
if dominance > 0.7: base += 10 # I'm controlling this
if momentum > 0.5: base += 10 # I'm on a roll
if credibility < 0.3: base −= 10 # I look bad — maybe stay quietThen it is blended 60/40 with an LLM strategy score (the LLM's read on whether speaking now is strategically smart), and the highest bid wins the floor.
This is where the system gets subtle. A high-momentum agent will aggressively bid for the floor. A credibility-crisis agent retreats, because the arithmetic makes silence the rational move, without any prompt saying so. That is the "strategic silence" scenario: an agent lets a rival keep talking and discredit themselves, then strikes when the numbers turn.
The whole flow, in one picture
Here is the life of a single turn, end to end:

And where it sits in the six-layer stack:

The six numbers sit at Layer 3. Raw events and relationships live below them; emotion, strategy, and language live above. Everything else reads from and writes to them, which makes them the single deterministic point the whole system passes through.
An honest wrinkle
One caveat worth stating: in the current update() path, a challenge reduces the speaker's credibility (the attacker pays for attacking), and the target_id is accepted but never used. For a deal-room simulation that is a defensible model, because aggression makes you look bad. But for coaching, training a founder to survive a hostile board, you would want to track credibility as the target: how much is the founder bleeding under attack. That asymmetry is not built yet.
Why six numbers, and why deterministic
This architecture makes the parts worth reasoning about explicit, bounded, and replayable. When trust collapses, you can point at the exact turn, the exact delta, the exact multiplier that did it. You can state-diff it, unit-test it, and replay the whole run while watching a single number drift.
The LLM still does what only an LLM can do: write a CFO's terse, furious email in character. It just no longer has to also remember whether the CFO is furious, or why, or what that means for the next five turns.

