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).