Live on MockProvider • Zero Cost • 42 Tests Passing

A society of synthetic people.
Without a swarm of expensive agents.

Persistent people. Evolving relationships. Social circles. One bounded inference per scene. Population scales to thousands at near-zero cost.

Dormant: 0 inference
Active: 1 call/scene
Circles: State
Relationships: State

The Central Equation

Five concepts, deliberately separate. Understanding this changes how you think about AI societies.

PERSON

Durable canonical identity — biography, personality, interests, social graph

ACTIVE
  • Stable UUID across restarts
  • Biography + personality + interests
  • Current state (mood, availability)
  • Never an agent, never a prompt

ROLE

Reusable behavior/capability set — assigned at zero cost

  • 29 seeded roles (friend, mentor, wildcard...)
  • Assigning creates zero inference
  • Composable: one person, many roles
  • Context filters relevance per scene

ACTOR

Ephemeral per-scene persona — materialized from Person + Roles + Relationships + Memory

  • Created at scene start, discarded after
  • Bounded: ≤5 memories, ≤4 relationships
  • Only selected speakers enter context
  • Dies when scene ends

MODEL

Capability class — social.mock → nano → standard → deep

  • Provider-neutral capability routing
  • Switching routes never touches Person
  • social.mock = $0, social.deep = premium
  • Escalation tracked, never implicit

GROKBOT

Optional premium inference route — a route, not an actor

  • Registered as social.deep provider
  • Never owns Person identity or state
  • Disabled by default — fully optional
  • Bridge contract: BoundedScenePackage

From Person → Society

Durable state builds up. Intelligence only activates when interaction requires it.

👤 Person — Person — The Durable Core

  • Stable UUID — persists across restarts, provider changes, years
  • Biography + personality + interests + current state (mood, availability)
  • Assigned roles (29 available: friend, mentor, wildcard...)
  • Social intensity: quiet | low | normal | social | very_social | do_not_disturb
  • Zero inference to create — pure structured state in SQLite
kernel.createPerson({
  name: "Emma Reyes",
  biography: "Product designer...",
  identity: { core: "warm, honest..." },
  interests: ["photography", "hiking"],
  currentState: { mood: 0.4 }
})

Why This Architecture?

The industry builds agent swarms. We built a society kernel. The difference is everything.

vs

20 People = 20 Permanent Agents

Each person gets a continuously running agent process. Memory, CPU, and inference costs scale linearly with population.

Cost ∝ Population × Time

Continuous Background Simulation

Agents 'think' even when nobody's talking. Idle time burns inference budget on manufactured activity.

Idle = Expensive

Unbounded Context Growth

Every agent remembers everything forever. Context windows explode, token costs compound exponentially.

Context ∝ History²

One Call Per Character Per Message

A 3-person group chat = 3 separate model calls. No shared context, no efficiency, 3x the latency and cost.

Calls = Speakers × Messages

Silent Retries on Failure

Failed calls retry automatically. A flaky provider silently multiplies your bill while you sleep.

Retries = Hidden Cost

Provider Lock-in

Identity tied to model. Switching from GPT-4 to Claude means rebuilding every persona from scratch.

Identity = Model

The Difference in One Equation

cost ≈ population × relationships × time

Naive agent swarms. Every person, every relationship, every second costs money.

cost ≈ meaningful generated interaction

GrokBot Society. Only selected speakers in a scene cost inference. Dormant = free.

This is not optimization — it is a different architecture. The runtime enforces it at every layer.

Composable Roles

29 reusable behavior definitions. Assign at zero cost. One person, many facets — never multiple agents.

Stranger

Tendencies

politeguarded

Capabilities

small talk

Acquaintance

Tendencies

friendlycurious

Capabilities

casual chatshared context

Friend

Assigned to Emma

Tendencies

warmsupportive

Capabilities

emotional supportshared activities

✓ Active in Emma's Actor when context-relevant

Close Friend

Tendencies

trustedvulnerable

Capabilities

deep conversationmutual aid

Best Friend

Tendencies

intimateloyal

Capabilities

complete honestyshared life

Romantic Interest

Tendencies

attentivefluttery

Capabilities

flirtingdate planning

Partner

Tendencies

committedintertwined

Capabilities

shared decisionslife planning

Spouse

Tendencies

bounddevoted

Capabilities

legal partnershipfamily building

Sibling

Tendencies

familiarprotective

Capabilities

shared historyfamily dynamics

Parent-like

Tendencies

guidingprotective

Capabilities

adviceemotional anchor

Cousin

Tendencies

familialrelaxed

Capabilities

family gatheringsshared relatives

Example: Emma Reyes

Product designer with a soft spot for analog cameras.

🎭 Friend🎭 Intellectual Friend🎭 Travel Companion🎭 Storyteller🎭 Listener

5 roles assigned. Zero inference cost. At scene time, only context-relevant roles compose into the Actor.

One Inference, Multiple People

A group chat is ONE structured generation returning multiple messages — never one call per character.

Live Scene Demo

How It Works

  1. 1Event intake: User message enters EventEngine as GROUP_INTERACTION
  2. 2Participant selection: ParticipantSelector scores all circle members (intensity, relationships, recency) → picks ≤3
  3. 3Context compilation: ContextCompiler builds BASELINE + ROLE + RELATIONSHIP + MEMORY sections — ONLY for selected speakers
  4. 4Budget decision: BudgetGovernor checks kill switch, caps, token limits → reserves 1 call slot
  5. 5Single inference: IntelligenceGateway routes to MockProvider (default) → returns structured SceneOutput with all messages
  6. 6Validation + Persistence: SocialDirector validates output → applies memory/relationship/timeline candidates → persists event
1
Model Call
Per scene, regardless of speakers
≤3
Speakers
Hard cap (hardMaxSpeakers)
$0
Default Cost
MockProvider = zero spend

What This Enables

  • 1,000 people, 15 active → dormant population adds $0
  • No per-message inference scaling
  • Context stays bounded, never explodes
  • Deterministic validation, no LLM-judging-LLM

God Kernel Pipeline

Every event flows through this deterministic pipeline. Intelligence is the last rung — most scenes stop before it.

Pipeline Stages

01

EVENT

USER_MESSAGE, GROUP_INTERACTION, PROACTIVE_REACH, SESSION_MESSAGE

Every interaction enters as a typed event with actor, participants, circle, payload

02

CACHE LOOKUP

Content-hash keyed on shape + modelClass + context sections

Hit → return $0 instantly. Miss → proceed. Dependencies = selected person IDs for invalidation

03

STATE / DB LOOKUP

Person, roles, relationships, circles, timeline, memory — all zero-inference

Only selected participants' relevant data retrieved. Privacy scopes enforced at read time

04

RELEVANCE SCORING

Deterministic scoring: intensity + circle + relationship + recency + topic

Hard cap: ≤3 speakers. Silent is valid (no eligible → no inference, no fake chatter)

05

PARTICIPANT SELECTION

Top-K scoring with recency penalty and intensity boost

Only selected speakers ever enter model context. Others remain completely dormant

06

CONTEXT COMPILATION

BASELINE + ROLE + RELATIONSHIP + MEMORY sections, bounded by token budget

≤12k tokens, ≤30 sections. circuit_explosion breaker hard-trips on overflow

07

BUDGET DECISION

Kill switch → per-event cap → background cap → token ceilings → tier gate → hourly/daily spend

Fail closed: any refusal → deterministic fallback. blockedCalls incremented for audit

08

INFERENCE (≤1 CALL)

IntelligenceGateway → ModelRouter → Provider → structured SceneOutput

MockProvider default ($0). Real providers only when budget allows. Validation before persistence

09

PERSISTENCE

Timeline, memory, relationships, followups, serendipity, telemetry — all applied

Event status: persisted | deterministic_fallback | silent | no_action. Full audit trail

One Call Per Event

maxCallsPerEvent = 1 enforced by BudgetGovernor. A 3-person scene = 1 call.

Fail Closed

Kill switch, budget ceilings, provider unavailability all block before inference → deterministic fallback

Zero Background Inference

backgroundModelCalls = 0 by default. Scheduled followups resolve deterministically at $0

Provider Independence

Switch models without touching a Person. Identity survives provider changes — routes are pure configuration.

MockProvider

Available
Built-inFloor

Deterministic structured output. Exercises full protocol. Default for all development.

scenejsontext
$0.000no live provider connected

DeterministicProvider

Available
Built-inFloor

Pure template/code cognition. No model at all. Still routed through gateway, subject to budget.

scenejson
$0.000no live provider connected

Nano (e.g., Haiku)

Needs API Key
Remote StubCheap

Fast, inexpensive real model. RemoteStubProvider becomes available when SOCIETY_NANO_API_KEY is set.

scenejsontext

Requires environment variable:

SOCIETY_NANO_API_KEY
Not connectedno live provider connected

Standard (e.g., Sonnet, GPT-4o-mini)

Needs API Key
Remote StubMid

Balanced capability. RemoteStubProvider available when OPENAI_API_KEY is set.

scenejsontext

Requires environment variable:

OPENAI_API_KEY
Not connectedno live provider connected

Deep (e.g., Opus, GPT-4o, Grok)

Needs API Key
Remote StubPremium

Highest capability. RemoteStubProvider available when GROK_API_KEY is set.

scenejsontext

Requires environment variable:

GROK_API_KEY
Not connectedno live provider connected

Default Capability Routes

All routes point to MockProvider by default ($0). Change routes in config to enable paid tiers.

Capability ClassProviderModelEst. Cost
social.deterministicdeterministictemplate-v1$0
social.mockmockmock-v1$0
social.nanomockmock-v1$0 (stub)
social.standardmockmock-v1$0 (stub)
social.deepmockmock-v1$0 (stub)

Identity Survives Provider Changes

Person Created

Emma exists in SQLite with biography, roles, relationships, memories

Route Changed

social.mock → social.standard via config. Zero Person migration.

Same Emma

Same UUID, same relationships, same memories. Only inference backend changed.

Cost Architecture

Population scales. Inference does not. Only active interactions cost money.

People500
5505005,000

$0.0275 per scene

3,500 input + 500 output tokens at $0.005/$0.020 per 1k. This is the core simulator profile, not a live provider quote.

Population Breakdown

Active: 15Dormant: 485

Only active people (those in circles, with relationships, recently interacted) ever enter model context. 485 dormant people = $0 inference.

1:1 Conversation

20 messages

16 calls
$0.44

16 calls @ $0.0275/scene

3-Person Group

15 messages

12 calls
$0.33

12 calls @ $0.0275/scene

30-Message Evening

30 messages

24 calls
$0.66

24 calls @ $0.0275/scene

Road Trip (24h)

40 messages

32 calls
$0.88

32 calls @ $0.0275/scene

Proactive (10 candidates)

0 messages

0 calls
$0.00

No inference needed

Combined Core-Verified Examples

$2.31

Core simulator profile — 500 people (15 active, 485 dormant)

Scenario totals use the core-verified token and rate profile. Population changes the dormant count, not these example workloads.

The Cost Ladder

CACHE

Identical scene context → instant return, $0

STATE / DB

Person, roles, relationships, circles — all zero inference

DETERMINISTIC

Relevance, selection, compilation, validation — pure code

PAID ROUTES

Remote provider classes are scaffolds. No real inference is connected.

CHATGPT

Disabled bridge contract. No ChatGPT inference or credits are connected.

GROKBOT

Disabled optional route contract. No GrokBot inference or credits are connected.

Why Population Does Not Drive Cost

Selection, Not Broadcast

ParticipantSelector picks ≤3 relevant speakers from circles. At population 5,000, 4,985 people never enter context.

Bounded Context

≤12k tokens, ≤30 sections per scene. Circuit breaker hard-trips on overflow. Context = constant.

One Call Per Scene

maxCallsPerEvent = 1. A 3-person group chat = 1 structured generation, not 3 separate calls.

Open Source & Verifiable

Every claim backed by code. Every guarantee tested. Run it yourself at $0.

Verification Pipeline

1

pnpm install

Install dependencies

pnpm install
2

TypeCheck

Strict TypeScript, zero errors

pnpm typecheck
3

Tests

42/42 tests passing

pnpm test
4

Dev Demo

Live society on MockProvider ($0)

pnpm dev
5

CLI Smoke

Start, chat, proactive, sessions, usage

pnpm society start && pnpm society chat ...

Architectural Guarantees (Tested)

No Provider Bypass

assertGatewalledCall() in every provider

One Call Per Event

maxCallsPerEvent = 1 enforced by BudgetGovernor

Zero Background Inference

backgroundModelCalls = 0 by default

Bounded Context

≤3 speakers, ≤12k tokens, circuit breaker

Fail Closed

Kill switch, budget, availability all block

Provider-Neutral Identity

Switch routes without touching Person

60-Second Quickstart

Clone
git clone https://github.com/M4G3LL4N0/grokbot-society.git
Install
cd grokbot-society && pnpm install
Verify
pnpm typecheck && pnpm test
Run Demo
pnpm dev
Use CLI
pnpm society start --db ./society.db

License & Independence

Licensed under Apache 2.0 — permissive, business-friendly, patent grant included.

Independent project. GrokBot Society is not affiliated with, endorsed by, or connected to xAI, Grok, Cursor, or any other company.

"GrokBot" in this project refers to an optional internal inference route name only.

Apache 2.0IndependentProvider-NeutralZero-Cost Default

Developer Quickstart

Working code in 60 seconds. MockProvider by default. Zero paid inference required.

4 Steps to a Living Society

1

Clone & Install

Get the code and install dependencies

git clone https://github.com/M4G3LL4N0/grokbot-society.gitcd grokbot-societypnpm install

Verification:

pnpm typecheck && pnpm test
2

Run the Demo

Boot a live society on MockProvider ($0)

pnpm dev

Verification:

Output shows 5 persons, 29 roles, 11 circles, 1 model call, $0 cost
3

Use the CLI

Persistent database with full operator control

pnpm society start --db ./my-society.dbpnpm society status --db ./my-society.dbpnpm society people --db ./my-society.dbpnpm society chat "Hello everyone!" --circle <INNER_CIRCLE_ID> --db ./my-society.db

Verification:

Interactive REPL with 3-speaker bounded scenes at $0
4

Explore the Society

Inspect persons, relationships, circles, landmarks, sessions

pnpm society person Emma --db ./my-society.dbpnpm society circles --db ./my-society.dbpnpm society landmarks Emma --db ./my-society.dbpnpm society session start evening_social --db ./my-society.dbpnpm society simulate --db ./my-society.db

Verification:

Identity cards, relationship dims, landmarks, cost simulator output

Code Examples

Create a Person

Zero inference — pure structured state

const kernel = createKernel(
  { maxPersons: 1000 },
  { clock: new SimulatedClock() }
);

const person = kernel.createPerson({
  name: "Aria Chen",
  biography: "Urban explorer and street photographer.",
  identity: { core: "curious, observant, quietly intense" },
  personality: { summary: "notices what others miss" },
  interests: ["photography", "urban exploration", "coffee"],
  currentState: { mood: 0.3, availability: "available", socialIntensity: "normal" },
});

console.log(person.id); // p_...

Assign Roles

Composable behavior at zero cost

kernel.assignRole(person.id, "friend");
kernel.assignRole(person.id, "creative_friend");
kernel.assignRole(person.id, "storyteller");
kernel.assignRole(person.id, "listener");

// At scene time, only context-relevant roles compose into the Actor
const actor = kernel.composeActorContext(
  person.id,
  "event:123",
  [person.id, otherPerson.id],
  circleId
);
// actor.roles = [friend, creative_friend, storyteller, listener]

Run a Group Scene

One inference, multiple speakers, bounded context

const innerCircle = kernel.circles.list()
  .find(c => c.name === "Inner Circle");

const event = await kernel.tell(
  "Anyone up for a spontaneous road trip this weekend?",
  { circleId: innerCircle.id }
);

// event.payload.sceneResult.output.messages = [
//   { personId: "p_...", text: "Sounds good — tell me more...", person: "Sam" },
//   { personId: "p_...", text: "Ha, that's a vibe. I'm in.", person: "Emma" },
//   { personId: "p_...", text: "I've been thinking about exactly that...", person: "Leo" }
// ];

console.log(`Model calls: ${kernel.stats().modelCalls}`); // 1
console.log(`Est. spend: $${kernel.stats().totalCost.toFixed(6)}`); // 0.000000

Inspect the Society

Full introspection at zero cost

// Person identity card
const card = kernel.identityCard(person.id);
console.log(card.name, card.archetype, card.essence, card.voice);

// Relationships
const rels = kernel.relationship.relationshipsFor(person.id);
rels.forEach(r => console.log(
  r.otherName, r.status, r.interactions,
  `${r.dims.familiarity.toFixed(2)}/${r.dims.trust.toFixed(2)}/${r.dims.affection.toFixed(2)}`
));

// Landmarks (shared history)
const landmarks = kernel.memory.landmarksFor(person.id);
landmarks.forEach(l => console.log("•", l.content));

// Cost simulator
const sim = kernel.cost.simulate({ population: 5000 });
sim.forEach(s => console.log(
  s.name, s.modelCalls, `$${s.estimatedSpend.toFixed(4)}`, s.note
));

MockProvider — The Default

The entire system boots and runs through MockProvider with no paid model configured. It is a deterministic, zero-cost stand-in that still exercises the full structured single-inference scene protocol: one call in, one SceneOutput (multi-message) out.

  • Deterministic structured output (SceneProviderPayload)
  • Exercises full gateway → cache → budget → provider → validation pipeline
  • Returns multi-message scenes with memory/relationship/timeline/followup candidates
  • Subject to all budget rules (kill switch, caps, token limits, tier gate)
  • Cost: $0.000 per call, forever

Key APIs at a Glance

Interaction

kernel.tell(prompt, { circleId })

Main interaction entry. Returns SocietyEvent with sceneResult.

Seeding

kernel.ensureSeeded()

Idempotent seed (5 persons, 29 roles, 11 circles, 10 rels, 5 landmarks).

Proactive

kernel.proactiveTick(circleId?)

Explicit proactive pass. Default off → 0 calls. Configurable relevance/cooldown/budget.

Identity

kernel.identityCard(personId)

Compact frozen Person snapshot (name, archetype, essence, voice, interests, goals).

Runtime

kernel.composeActorContext(...)

Bounded Actor for one scene. Person + Roles + Relationships + Memory + SceneRef.

Telemetry

kernel.usage()

Telemetry: calls, tokens, spend per person/circle/provider, blockedCalls, escalations, trips.

Safety

kernel.setKillSwitch(true)

Fail-closed kill switch. All inference blocked → deterministic fallback. blockedCalls increments.

Sessions

kernel.sessionStart/Context/End

Long-session abstraction. Rolling window (6 msgs) + participant cards (4).