Anukara

Anukara · a simulation engine

A simulation engine for worlds of people who decide.

We built a grammar, a runtime and an SDK for worlds of people. A cartridge declares the people, the rules and the actions they may take. The engine gives each person turns on their own routine, records every decision as an event with an id and a cause, and branches from any checkpoint.

Recording · world 01a164f5 · arm A · 22 October 2026

day 30 of 30
  • turns
  • actions
  • social
  • host events
  • other engine events
  • crowd step

day 30 · 6,251 events · 364 host · 5,350 state changes · crowd step 10

events
68,886
in the event store
turns
5,185
200 people, each on a routine
prompt tokens
106.1M
29.5M cached · 27.8%
model spend
$11.74
claude-haiku-5-5
event ledger · newest last54 of 68,886 events, sampled across the run
  1. [1a3adc6c] [day 26] Sarah Ashford: inactive
  2. [84003907] [day 26] Derek Calloway: inactive
  3. [e7b81805] [day 30] the crowd: 200 replies, 40 likes on 5 posts
  4. [7132057d] [day 30] the host: cycle_closed → Matthew Stroud, downgrade
  5. [ebdff931] [day 30] the host: cycle_closed → Marcus Hale, downgrade
  6. [9a1d9848] [day 30] the host: cycle_closed → Donna Pickering, downgrade
  7. [a1f26ce6] [day 30] the host: cycle_closed → Chloe Bowman, full_renewal
The real recording of arm A of the Breach run, 22 October 2026, read from the engine's event store: 200 people and a 300-account crowd over 30 simulated days, 68,886 events, 5,185 turns, 106M prompt tokens of which 29.5M cached, $11.74 of model spend and 46 minutes of wall clock on claude-haiku-5-5. The names are fictional cast members. While the cursor moves, tokens and spend are the run totals shared out by turns; events and turns are counted per day.

One real run · 22 October 2026 · a breach-disclosure study run by a host application

  • 200 + 300cast people and crowd accounts, per arm
  • 30 daysof simulated time, each person on a routine
  • 46 minof wall clock, both arms in parallel
  • $11.70model spend per arm on Haiku 5.5, capped at $24
  • 14,864model calls, each logged with its prompt
  • 2 of 2arms reached the horizon, no fatal errors

Cartridges

A cartridge declares the world.

A cartridge is JSON checked against our grammar: 17 JSON schemas that also generate the engine's Go types. The gateway refuses anything it cannot run, and cartridges.dryRun says so before admission does.

peopleentities
Named people with state, persona traits, goals and the scopes they belong to.
rulesrules
CEL conditions that fire on an event, on an interval, after a person acts or after someone acts against them.
actionsaction_registry
What a person may do, with typed parameters, a visibility and the effects it applies.
scopesscopes
Rooms with members or public visibility, named or anonymous attribution, and the visible_state a member can read.
pacingpacing
Routines at declared instants, profiles that bundle them, tempo shifts and pokes.
terminationtermination
The horizon in logical time, event and token ceilings, and exit conditions in CEL.
effects19 primitives
  • set
  • add
  • subtract
  • transfer
  • block
  • unblock
  • create_entity
  • destroy_entity
  • set_archetype
  • set_profile
  • emit
  • corpus_write
  • knowledge.attest
  • attach_hook
  • detach_hook
  • create_scope
  • destroy_scope
  • add_to_scope
  • remove_from_scope
cartridge excerptillustrative
{
  "entities": [{
    "id": "p_0017", "name": "Priya Natarajan",
    "scope_ids": ["rowing_club"],
    "state": { "member": true, "times_told": 0 },
    "persona_traits": { "ad_trust": 0.29 },
    "rules": [{
      "id": "advocate", "name": "Told three friends",
      "trigger": "after_i_act", "action_type": "tell_friend",
      "condition": "agent.state.times_told >= 3",
      "effects": [{ "primitive": "emit", "event_type": "study.advocate" }]
    }]
  }],
  "action_registry": [{
    "id": "tell_friend", "target": "entity", "visibility": "public",
    "parameters": { "message": { "type": "string", "required": true } },
    "effects": [{ "primitive": "add", "apply_to": "invoker", "path": "state.times_told", "value": 1 }]
  }],
  "scopes": [{ "id": "rowing_club", "visibility": "members", "visible_state": ["member"] }],
  "pacing": { "routines": [{ "id": "evening", "every": 1440, "anchor": 1200, "turns": 1, "actions": ["tell_friend", "wait"] }] },
  "termination": { "max_logical_time": 43200 }
}
Field names are the grammar's. The clock here counts minutes, so 43200 is thirty days.

Grammar in, English out.

The host writes JSON the grammar validates. Nothing in a person's turn is JSON: state, events, the room and the crowd's reaction arrive as sentences, each event with an id the person can cite.

illustrative

what the host sends

{
  "id": "p_0017", "name": "Priya Natarajan",
  "scope_ids": ["rowing_club"],
  "state": { "member": true, "times_told": 3, "decision": "wait" },
  "persona_traits": { "ad_trust": 0.29, "organiser": 0.71 }
}

what the person reads

Your current state:
- member: true
- times_told: 3
- decision: wait
- profile.ad_trust: 0.29
- profile.organiser: 0.71

Where you are: Rowing club, a Tuesday and Thursday crew that has rowed together for six years.

Turns

What happens on a turn.

When a routine falls due, the engine builds the person's prompt from their context, their state, the events since their last turn and the memories recalled for this moment. The model answers with one tool call. Effects apply, the scribe rewrites the memory journal, and everything lands in an event-sourced history.

events feed the next turnpersona and traitswho they are, in their voicestate and visible roomsvisible_state of each scopeevents since the last turnin English, each with an idrecalled memoryjournal entries, ranked by jevthe promptbuilt fresh each turnplain English, no JSONeach event with its idthe decisionone tool call: an action,its parameters and theevent ids it citesclaude-haiku-5-5the event logaction.completedstate.changed rowsevery event carriesid · time · sourcetarget · causereplayable, branchablethe scriberewrites the memory journalmemory for the next recallpersona and traitswho they are, in their voicestate and visible roomsvisible_state of each scopeevents since the last turnin English, each with an idrecalled memoryjournal entries, ranked by jevthe promptbuilt fresh each turnplain English, no JSONthe decisionone tool call: an action, itsparameters, the ids it citesclaude-haiku-5-5the event logaction.completedstate.changedid · time · sourcetarget · causethe scriberewrites thememory journal

One person's 26 turns · Joshua Bolton · arm A of the Breach run

26 turns on 10 of 30 days. Prompts grew from 10,787 to 19,689 tokens as the month filled his history, 429,124 in all. 12 turns ran memory recall steps. He acted with check_account, review_terms, use_premium once each, chose inactive 15 times, and 8 evening turns recorded no action.

day 1
3
6
10
11
16
17
21
24
26

day 21 · 10:01 · chance_step_1 · 18,753 prompt tokens · 1,357 completion · 3 memory recall steps · use_premium

  • an action
  • chose inactive
  • evening turn, no action recorded
  • memory recall steps
  • bar height: prompt tokens, up to 19,689

His day-16 turn in the event store

id
f05883b6
type
action.completed
logical time
22,203 · day 16, 10:03
source
Joshua Bolton
action
inactive

Checkpoints and branches

Fork from any completed step. Keep both arms.

Every completed step is a checkpoint. A child world spawned from one with fork_tick carries the same people with the same memories and reads its parent's history up to that moment, then diverges. In the Breach study the two arms differ only in when and how the company tells its customers.

arm A · early, plain noticearm B · waits for the official notice
day 1A 200B 200

Day 1. The breach happens. Nobody outside the company knows yet.

arm A · end of day 30

Arm A kept 164 of 200: 24 downgrades, 12 switched provider, none cancelled.

arm B · end of day 30

Arm B kept 144 of 200: 36 downgrades, 18 switched, 2 cancelled. The tipped-off customers held back until the notice, then moved together.

End-of-run counts are from the run of 22 October 2026. The day-by-day shape between them is illustrative.

Metering, allowances and cost per decision

A ceiling before the first call. Cents after.

Casting admits the cartridge, pins a price table and plans every routine, so the gateway quotes a dollar ceiling before any model call. Nothing is spent until a job starts with an allowance. The wallet holds it, each batch reserves against it, every call settles to the cent, and the world stops at the cap.

  1. 01 · quote

    A dollar ceiling for the cartridge, broken down by profile, before any call.

  2. 02 · allowance

    The job starts with dollars in a wallet; top up mid-run if you want more.

  3. 03 · reserve

    Each batch of turns reserves against the allowance before it runs.

  4. 04 · settle

    Every model call settles to the cent and emits a usage event; the cap is a hard stop.

authorization gate Optional: the host's endpoint answers before each run, turn or model call, with an HMAC signature on every ask.

200

10named, with memory1,000

30

1on the world's calendar90

300

0counted, no LLM calls2,000

Model

calibration point · the Breach run

estimated model spend, per arm

$11.70

two-arm fork $23.40 · same wall clock, arms run in parallel

wall clock
≈ 46 min
model calls
≈ 7,430 per arm
agent-days
6,000
per agent-day
$0.00195

cast $10.80crowd $0.901.0× the Breach run

Measured basis: the Breach run averaged about $0.0016 per model call and $0.002 per agent-day, crowd and memory included.

Calibration · measured

The breach-disclosure run of 22 October 2026: 200 cast agents and a 300-account crowd per arm, 30 simulated days, on claude-haiku-5-5. $11.70 per arm, $23.39 for both, 14,864 model calls, 46 minutes wall clock with both arms in parallel. About $0.002 per agent-day, crowd and memory included.

The formula · estimate

spend ≈ agents × days × $0.0018 × model
      + crowd × days × $0.0001

$0.0018 is the Breach run's $11.70, less its crowd at $0.0001 per account-day, over its 6,000 agent-days. Wall clock assumes that run's pace of about 130 agent-days a minute per arm.

Per decision · measured

On 3–5k-token prompts, one decision costs about $0.0006 on Haiku and about $0.0011 on DeepSeek Flash, roughly 1.8× Haiku. The DeepSeek figures here apply that ratio to the Haiku run; no full DeepSeek run backs them.

Models

The model slot, as it stands today.

Every model call goes through one gateway with a price table pinned per job, so a world's cost does not move under it mid-run.

  1. Claude Haiku 5.5

    in use

    decides and speaks for a person

    Runs every person's turns today, including the Breach run.

  2. DeepSeek Flash

    priced

    priced, available through the same gateway

    About $0.0011 per decision on 3 to 5k-token prompts, 1.8 times Haiku.

  3. OpenAI models

    priced

    priced, available through the same gateway

    Same route, same metering, same price table pinned per job.

  4. jev

    ours

    our own non-LLM model: crowd reactions and memory ranking

    Content-keyed and cached across snapshots and branches, so a replay makes zero LLM calls for them.

API surface

One gateway, typed end to end.

A host product drives the engine through 153 routes. The SDK is generated from the gateway's OpenAPI, so a misspelled field is a compile error rather than a failed run.

  • 153HTTP routes on one gatewayCartridges, jobs, worlds, events, interviews, usage and archives.
  • SDKTypeScript, generated from the OpenAPIEvery body, query and response typed. cartridges.dryRun checks a cartridge as admission will.
  • WebhookssignedAn HMAC over the timestamp and the body on every delivery.
  • MCPthe same routes, for agentsAn agent can admit a cartridge, start a job and read the record.
  • A2Aan outside agent plays a personaA person in the world can be driven by an agent you run.
import { LaplaceClient } from "@anukara/engine-sdk";
const client = new LaplaceClient(config);

const verdict = await client.cartridges.dryRun({ contract_definition: cartridge });
if (!verdict.ok) throw new Error(verdict.errors.map((e) => e.msg).join("\n"));

const { cartridge_id } = await client.cartridges.admit({ contract_definition: cartridge });
const quote = await client.jobs.quote({ cartridge_id });
console.log(quote.total_usd, quote.pacing_preview.ceilings.decisions);

Scale · on the development gateway, 2 November 2026

What exists, counted.

One founder built all of it, starting in February 2026. The counts are read from the repository and the development gateway; the model calls and spend include smoke runs.

lines of code, thousands, rounded

  • Go tests349k
  • TypeScript221k
  • Go source211k
  • Python91k
  • 7,594Go test functions
  • 5,099TypeScript test cases
  • 32wet-test scenarios against the full stack
  • 17grammar schemas
  • 34finished worlds
  • 167,387model calls
  • $105total model spend

the Breach run Two arms, each 200 people and a 300-account crowd, 30 simulated days in 46 minutes, $11.74 and $11.65 of model spend, 14,864 model calls.

Principles

Four rules the engine keeps.

When a shortcut breaks one of them, the shortcut goes.

  1. 01

    People read English.

    Nothing in a turn prompt is JSON: state, events, the room and the crowd's reaction all arrive as sentences, each with an id to cite.

  2. 02

    The crowd is counted.

    The crowd appears as counts and grouped replies, never quoted; the cast are the named people who matter, and only they speak in the record.

  3. 03

    Correctness over model spend.

    The host pays the bill, so the engine never trades a correct decision for fewer tokens; the allowance is the brake, not the prompt.

  4. 04

    Every line has a receipt.

    An id, a time and a cause on every event, and decisions cite the lines that drove them.

Applications

What the engine is for.

  1. 01

    Lokara

    Business decisions put to simulated people. The first application built on the engine.

  2. 02

    Company digital twins

    A company's people, teams and rules declared as a cartridge, to see how a change moves through them.

  3. 03

    Agent evaluation and training

    Worlds as replayable, scoreable environments, with an outside agent playing a persona over A2A.

  4. 04

    RL environments for labs

    Declared rules, recorded causes and branchable checkpoints give an environment with a full trace per episode.

  5. 05

    Games

    Characters who remember, keep routines and act on what they saw, under rules the designer declares.

The first application

Lokara

For research and product teams with a decision to make. Built on this engine through the same SDK.

Open Lokara

Lokara rehearses a decision on simulated people before your customers see it. Build the audience, run each option, and read every decision with its reason.

uselokara.com

Lokara's run screen for the First 100: two simulations from one start over ten periods, A with no reward at 47% signed up at the end, B with a 20 dollar referral reward at 38%.Lokara, the Universe screen of the First 100

Founder

Vighnesh Bheed

Saarbrücken, Germany

Ten years of engineering. Neural networks and digital twins for experiment design, computer-vision models for defect detection on industrial machines, and an agent-verification platform. Building Anukara and Lokara since February 2026.