Session API

Embeddable npm runtime — session lifecycle, command dispatch, snapshot extraction, and fork/restore patterns.

What this uses

@its-not-rocket-science/ananke/session createSession runSession forkSession serializeSession src/session.ts src/sim/kernel.ts src/sim/commands.ts docs/host-contract.md docs/integration-primer.md

The session facade wraps the deterministic kernel tick loop in a managed lifecycle. It is the recommended integration surface for host applications — prefer it over calling the kernel directly. Exported under the session subpath.

Tier-1 stable API. Covered by the semantic versioning contract in STABLE_API.md.

Lifecycle diagram — static preview

static preview
createSession(config)
init world seed,
entity map
runSession(session, cmds)
step N ticks,
emit events
forkSession(session)
clone snapshot,
branch world
serializeSession(session)
JSON envelope,
portable state

A forked session shares no mutable state with its parent. Both branches can be stepped independently. Determinism is preserved: given the same command sequence, both produce identical tick-by-tick outcomes.

Import example

import {
  createSession,
  runSession,
  forkSession,
  serializeSession,
} from '@its-not-rocket-science/ananke/session';

const session = createSession({
  worldSeed: 42,
  tickRateHz: 20,
  entities: [
    { id: 1, label: 'knight', archetype: 'FIGHTER' },
    { id: 2, label: 'archer', archetype: 'ARCHER'  },
  ],
});

const result = runSession(session, [
  { tick: 0, type: 'MOVE', entityId: 1, target: { x_Sm: 10000, y_Sm: 0 } },
  { tick: 5, type: 'ATTACK', entityId: 1, targetId: 2 },
]);

console.log(result.events);          // typed SimEvent[]
console.log(result.finalTick);       // last stepped tick

const snapshot = serializeSession(session);  // → JSON string

Session envelope — JSON shape

static preview
{
  "anankeVersion": "0.5.0",
  "sessionId":    "s_42_1748736000",
  "worldSeed":    42,
  "tickRateHz":   20,
  "currentTick":  100,
  "entities": {
    "1": { "id": 1, "label": "knight", "vitals": { "shock_Q": 1820 }, "...": "..." },
    "2": { "id": 2, "label": "archer", "vitals": { "shock_Q": 3200 }, "...": "..." }
  },
  "forkDepth":    0,
  "parentSessionId": null
}

All numeric fields using fixed-point arithmetic store integer Q values (scale 65536). Divide by 65536 to get the floating-point equivalent for display purposes only — never use floats in the simulation path.

Envelope validator