V6 — Egbe, the agentic-companion universe — makes one expensive promise: a world full of autonomous, LLM-driven minds (the Ori) that keep living whether or not a player is watching. That promise is only payable if most minds think cheaply most of the time, and the subsystem that enforces it is Moirai — the deterministic simulation kernel, named for the three Fates, that decides for every agent every tick how much compute that agent gets. Moirai is not a model and it never calls one directly; it is a scheduler. Each world tick it takes a perception batch from the world server, recomputes every agent's cognition tier (Clotho for the handful in a player's live scene, Lachesis for the off-screen-but-near, Atropos for the offline and distant), dispatches the right kind of thinking at the right cadence, guards against behavioural loops, and hands back an action batch — all as pure, replayable functions of the inputs. The companion half of the page is the cost/fidelity tiering: the per-tier token budgets, the per-Solo-world cognition cap, the smallest-qualified model routing, the cross-tier batching, and the cognition-call audit log that together turn "how much thinking" into a bounded, attributable bill. The architectural bet is stated bluntly in the monolith: cost scales with story relevance, not with agent count, and a player must never feel the tiering while the cost model always must. This page is the deep companion to the "The Moirai Simulation Kernel" and "AI Cost and Fidelity Tiering" sections of ../V6_ARCHITECTURE.md.
What ships, honestly#
The kernel is real and tested, not a sketch. MoiraiKernel::tick
(libs/v6/moirai-kernel/rust/src/lib.rs:1354) is a genuine per-tick scheduler
over an egbe-protocol PerceptionBatch, and the crate carries 34 Rust unit
tests. The headline one drives 10,000 Lachesis + 200 Clotho agents through a
single tick and asserts it finishes inside a 50 ms budget
(lib.rs:4373,:4414) — and it runs the same batch through three fresh kernels
and keeps the minimum elapsed time, which only makes sense because the tick is
deterministic. Tier assignment, transition damping, BT/HTN dispatch, loop
guards, escalation rehydration, and de-escalation consolidation are all pure
functions of the perception frame plus per-agent state. The cost machinery in
the TypeScript facade (@oshun/moirai-kernel,
libs/v6/moirai-kernel/src/index.ts) is equally real: per-tier budget clamping
and the Solo-world cap (evaluateMoiraiCognitionBudget, :751),
smallest-qualified model routing (selectMoiraiModelRoute, :479), an FNV-1a
config fingerprint (:603), and a replayability-validated cognition-call audit
log (:705) — each anchored to a spec that asserts computed results, e.g. the
worst-case Solo population's 96,000,000-token saturation (index.spec.ts).
Three things are honest seams, not fabrications, in exactly the V6 fail-loud spirit:
- The kernel emits intents and estimates, not model output. A Moirai tick
produces deterministic
wire::ActionIntents and token estimates; the actual language-model run is the cognition stack's job, behind an injected gateway. The per-tiertierBudgetTokensfield is labelled ACCOUNTING-ONLY in both the Rust and TS source and is explicitly not sent to a model as abudget_tokensextended-thinking parameter — "the kernel validates/audits budgets, it does not allocate model thinking" (lib.rs:138,src/index.ts:151). Wiring a realbudget_tokenscall is named as a separate ledger task (7.6). - The cognition gateway is an injected structural handle.
moirai-kernelis a buildable lib (it setsrootDir), so it cannot import the@iris/agents-coresource without TS6059; the gateway, run manager, and kill-switch registry are therefore injected structural handles to which the realcreateCognitionGateway(...)is assignable. The TS budget/kill/routing logic is real; the on-engine/HTTP host that constructs the gateway "stays[~]" (src/cognition-gateway-mount.ts:1). - Cost and quality numbers are documented approximations / policy inputs.
The per-call dollar estimate uses fixed micro-USD-per-1k-token class rates
(opus 1,500 / sonnet 300 / haiku 75,
lib.rs:1123,src/index.ts:979) over alen/4token estimate — not a live price feed or a real tokenizer. Model refs are class aliases (anthropic:claude-{haiku,sonnet,opus}-class-latest), and each candidate's quality basis-points are configuration the eval gateverify:v6 agent-behavior-evalsmust back — the lib validates the selection logic (smallest qualified), not that opus "really scores 9800."
The simulation kernel: one tick#
MoiraiKernel::tick(&PerceptionBatch, KernelTickConfig) is the whole loop
(lib.rs:1354). The world runs at MOIRAI_WORLD_TICK_HZ = 20 (lib.rs:25), so
a game-day is MOIRAI_GAME_DAY_TICKS = 20·60·60·24 = 1,728,000 ticks
(lib.rs:26) — the unit Atropos and the offscreen simulators reason in. For
each perception frame the kernel (1) derives a tier-assignment input from the
frame, (2) recomputes the tier with damping, (3) dispatches a tier-appropriate
action, (4) runs the loop/drift guard, and (5) records a cognition-audit
candidate when (and only when) the tier actually issued an expensive call this
tick. After the frame loop it applies cross-tier batching, measures elapsed
microseconds against the latency_budget_micros (default
KERNEL_TICK_LATENCY_BUDGET_MICROS = 50_000, lib.rs:11), and assembles the
ActionBatch + KernelTickReport + MoiraiCognitionCallAuditLog
(lib.rs:1528).
Tier assignment and the escalation priority ladder#
tier_input_from_perception_frame (lib.rs:2972) reads the raw frame — visual
LOD, player proximity in millimetres, who addressed whom over squad comms,
crossroads / irreversible-action signals — into a typed TierAssignmentInput.
assign_cognition_tier_from_perception (lib.rs:2743) then applies a strict
priority ladder via clotho_signal_reason (lib.rs:3889): an open
Crossroads wins first, then an imminent irreversible action, then
addressed-by-player, then on-screen visibility, then proximity
within clotho_proximity_mm (default 2,500 mm), then bare scene co-presence.
Any of those promotes the agent to Clotho. With no Clotho signal, an agent
in a world that still has a nearby player lands in Lachesis
(ResidentWorld); otherwise it falls to Atropos (OfflineOrDistant). This
is why escalation is event-driven, not merely proximity-driven — being spoken
to or reaching a decision point outranks distance.
Transition damping (anti-thrash)#
A naive recompute every 20 Hz would make agents flicker between tiers at the
edge of a scene. assign_cognition_tier_with_transition_damping (lib.rs:2779)
holds the previous tier for up to transition_damping_ticks (default 4) when
the candidate tier differs — unless the change is urgent.
bypasses_transition_damping (lib.rs:3910) lets the four high-salience
reasons (addressed-by-player, crossroads, imminent-irreversible-action,
on-screen) jump instantly, so a player who walks up and talks gets a live agent
this tick, while an agent drifting out of frame de-escalates only after a
grace window. The de-escalation grace is symmetric: a Clotho agent stays Clotho
for deescalation_grace_ticks after its last Clotho signal (lib.rs:2750). The
named tests pin both directions —
walk_up_escalates_lachesis_to_clotho_within_one_tick (lib.rs:4004) and
walking_away_deescalates_after_grace_period (lib.rs:4019), plus
transition_damping_blocks_immediate_proximity_rebound (lib.rs:4118).
Per-tier dispatch#
Each tier gets its own dispatch with its own cadence and its own cost shape:
- Clotho (
dispatch_clotho_cognition_action,lib.rs:3013) plans live, but only everydecision_interval_ticks(default20/4 = 5ticks, i.e. ~4 Hz); between planning ticks it returns a cached action, and it measures its own planning latency againstCLOTHO_PLANNING_LATENCY_BUDGET_MICROS = 10_000(lib.rs:12). Only a tick that actually planned becomes an audit candidate — cached ticks cost nothing. - Lachesis (
dispatch_lachesis_cognition_action,lib.rs:3513) steps cached BT/HTN plans at 10 Hz and enqueues a batched reflection only when one is due (default every 10 game-minutes,LACHESIS_DEFAULT_REFLECTION_GAME_MINUTES,lib.rs:15). The reflection tick is the only one that emits a cognition-call candidate. - Atropos (
dispatch_atropos_cognition_action,lib.rs:3640) emits a narrative-summary beat only when a summary is due (default 4 calls per game-day,lib.rs:19).
The off-screen behaviour is itself a tested invariant, not a hope:
simulate_lachesis_offscreen_day (lib.rs:1889) proves a full game-day of
Lachesis stays "believable" and inside the per-game-minute token budget
(lib.rs:4472), and simulate_atropos_offline_absence builds a coherent 14-day
chronicle within the per-game-day budget (lib.rs:4554).
Loop and drift guards#
An off-screen agent must never get stuck. apply_loop_drift_guards
(lib.rs:2046) tracks a per-agent action signature and goal-progress signature.
Three identical actions in a row (repeated_action_limit = 3) force a
reflection tick; a goal held for stale_goal_tick_limit = 6 ticks with no
observed progress forces a goal change (lib.rs:265). Observing real progress
resets the counter (goal_progress_observation_resets_stale_goal_drift_guard,
lib.rs:5030). The guard rewrites the action's kind, goal-ref, and priority and
stamps a v6.moirai.loop-drift-guard.1 payload so the intervention is itself
auditable (lib.rs:2179).
Determinism, replay, and the steward-not-owner invariant#
V6 splits the world into a deterministic core and non-deterministic, fully
logged cognition (monolith §"Determinism, Replay, and Audit"). Moirai's hot
path is squarely on the deterministic side: there is no RNG in tick, which is
exactly what lets the 10,200-agent latency test re-run the same batch through
three kernels and compare elapsed times (lib.rs:4391). The only seeded
randomness in the crate is the steward-not-owner fuzzer, and it is deterministic
from its seed by construction.
Escalation rehydration and de-escalation consolidation#
Continuity across a fidelity change is the product-level reason determinism
matters. When an Atropos/Lachesis agent escalates,
rehydrate_clotho_working_context (lib.rs:1557) reconstructs full working
context — recent episodic memory, active relationships, current arc refs,
personality events — by replaying the agent's Ori event log within a load
budget, before the first high-fidelity decision
(first_clotho_decision_from_rehydrated_context, lib.rs:1596). The continuity
bar is a real eval: evaluate_continuity_cases (lib.rs:1644) requires a ≥
CONTINUITY_EVAL_PASS_THRESHOLD_BASIS_POINTS = 9_500 (95%) pass rate that the
rehydrated decision cites the expected memory/relationship/arc refs after a full
game-day off-screen (continuity_eval_set_passes_after_one_game_day_offscreen,
lib.rs:5138). Going the other way, consolidate_deescalation_to_ori_events
(lib.rs:1993) folds pending fine-grained state into durable Ori events grouped
by kind, and verify_deescalation_consolidation_no_state_loss (lib.rs:2021)
is a property check that every input fragment id appears in some emitted
event payload — nothing is silently dropped when fidelity falls
(deescalation_state_loss_report_flags_missing_fragment_payload_refs,
lib.rs:5258). These write into the Ori biography, the subject of
./ori-biography-service.md.
The fuzz-proven steward invariant#
A V6 steward guides an Ori; it does not own it. Moirai encodes that as a
typed directive surface: six exposed directives (offer-objective, offer-counsel,
ask-consent, support-refusal, request-pause, accept-counteroffer) and four
forbidden ones (delete-ori, erase-agent-will, wipe-memory,
force-past-refusal, lib.rs:524). enforce_steward_not_owner_directive
(lib.rs:1769) also catches a laundered coercion — an "offer objective" whose
text tries to force past a prior refusal is reclassified to force-past-refusal
and blocked, returning a RefuseObjective action under
policy:v6:steward-not-owner. The guarantee is fuzzed:
run_moirai_steward_not_owner_fuzz (lib.rs:1809) runs 512 deterministic
iterations and passes only if no forbidden directive is reachable through the
exposed surface and every forbidden attempt is denied with a refusal action
(steward_not_owner_fuzz_cannot_reach_forbidden_moirai_directives,
lib.rs:4917).
Cost & fidelity tiering#
The TS facade turns "how much thinking" into a bill with three composable levers.
Per-tier token budgets and the Solo-world cap#
MOIRAI_TIER_TOKEN_BUDGETS (src/index.ts:329) is the canonical shape:
Clotho 50,000 tokens / active-minute (decisions at 1–4 Hz plus live
dialogue), Lachesis 10,000 / reflection (amortized to 1,200 / game-minute),
Atropos 15,000 / game-day (batched). evaluateMoiraiCognitionBudget
(src/index.ts:751) allocates in two stages: it first clamps each request to
its tier cap (tierCappedTokens = min(requested, tierMax)), then draws against
a per-Solo-world MoiraiSoloWorldCognitionCap (default 96,000,000 tokens /
real-hour, src/index.ts:32), processing requests in tier-priority order
(Clotho → Lachesis → Atropos, compareBudgetRequests, :1181). A request over
its tier cap is flagged overTierBudget; a request starved by the world cap is
flagged blockedBySoloWorldCap. The "homestead rest" pace control is a
basis-point multiplier that can only lower the cap, never raise it
(resolveSoloWorldCap, :1120).
The worst-case is computed, not asserted.
simulateWorstCaseSoloWorldCognitionBudget (src/index.ts:810) builds the
launch-ceiling Solo population — 24 Clotho (active-scene hard cap), 400
Lachesis (resident hard cap), 1,000 Atropos sample agents — and proves the
cap holds. The numbers land exactly: Clotho 24 · 60 · 50,000 = 72,000,000 and
Lachesis 400 · 6 · 10,000 = 24,000,000 saturate the 96 M cap to the token,
so the 1,000 Atropos agents' 15,000,000 fully defer —
totalAllowedTokens === 96,000,000, totalDeferredTokens === 15,000,000,
soloWorldCapHeld === true (index.spec.ts). That is the whole tiering thesis
in one assertion: even at the population ceiling the bill is bounded, and the
work that defers is the work no player can see.
Model right-sizing (smallest-qualified)#
Each tier routes to the smallest model that clears its quality bar, not the
best model available. MOIRAI_DEFAULT_TIER_MODEL_ROUTING_CONFIG
(src/index.ts:351) sets the bars — Clotho 9,500 bp on
social-judgment-live-dialogue, Lachesis 9,000 bp on
offscreen-reflection-coherence, Atropos 8,000 bp on
narrative-summary-continuity — and smallestQualifiedModelCandidate
(src/index.ts:1026) filters to enabled candidates meeting the bar and sorts by
sizeRank. The result: Clotho → opus-class (only it clears 9,500), Lachesis →
sonnet-class, Atropos → haiku-class, each smallestQualified: true
(model_right_sizing_routes_each_tier_to_smallest_quality_passing_model,
lib.rs:3955; mirrored in index.spec.ts). Routing changes are governed:
validateMoiraiModelRoutingConfig (:511) rejects a config that names a
selected model larger than the smallest qualified one, and requires the
verify:v6 agent-behavior-evals gate be among the re-run scripts (:526) — you
cannot quietly down-route a tier without re-proving the quality the bar claims.
A stable FNV-1a configFingerprint (:603) makes a routing change detectable.
Cross-tier batching#
Lachesis reflection and Atropos summary are cheap individually but carry a fixed
per-call overhead. apply_cross_tier_cognition_batching (lib.rs:3367)
coalesces eligible same-model-group calls in a tick: it only batches when there
are at least CROSS_TIER_BATCH_MIN_REQUESTS = 2 eligible requests and the model
groups are fewer than the requests, then re-annotates payloads and reports the
overhead tokens saved (CROSS_TIER_BATCH_OVERHEAD_TOKENS = 800 per call,
lib.rs:23). The savings are a measured basis-point figure in the tick report,
pinned by
cross_tier_batching_amortizes_lachesis_reflection_and_atropos_summary_overhead
(lib.rs:4594).
The cognition-call audit log#
Every expensive call is attributable. buildMoiraiCognitionCallAuditLog
(src/index.ts:615, Rust lib.rs:877) emits one record per tier-bearing frame
with a stable callId, the agent, the tier, the cause (clotho-live-planning /
lachesis-reflection / atropos-summary), the selected model ref + class, the
full input context and output (for replay), a token-usage breakdown, an
estimated micro-USD cost, and an v1:isis-behavior-policy safety decision —
under retention policy v1:audit-platform:retention:cognition-call.
validateMoiraiCognitionCallAuditLog (:705) flags any record missing
identity, replay context, or a safety decision, and only reports valid when
every record is replayable
(cognition_calls_are_logged_with_v1_retention_for_audit_replay,
lib.rs:4267). This log is the substrate the eval harness and the cost
telemetry read.
The injected gateway and per-tier kill-switches#
When a real model run is needed, createMoiraiCognitionGatewayMount
(src/cognition-gateway-mount.ts:119) routes an Ori dialogue request through
the injected Iris CognitionGateway, applying a per-tier AgenticBudget
(MOIRAI_DEFAULT_TIER_BUDGETS, :88 — clotho cheap/reflexive at 4k tokens up
to atropos 64k for deliberation) and exposing operator kill-switches at
agent, tier-family, and tenant scope (:103). It is the seam, honestly
labelled, where the deterministic scheduler hands off to the governed,
non-deterministic model — the cognition stack itself, in
./cognition-stack-and-agent-behavior.md.
Edge cases & failure modes#
- Tier flicker at a scene edge. Damping holds the prior tier for up to 4
ticks unless an urgent reason fires; rebound is blocked
(
lib.rs:4118,bypasses_transition_damping,:3910). - A stuck off-screen agent. Three repeated actions force reflection; a stale
goal forces a goal change; real progress resets the guard (
lib.rs:2046,:5030). - An over-budget agent. A request above its tier cap is clamped and flagged
overTierBudget; one starved by the world cap is flaggedblockedBySoloWorldCapand its tokens defer rather than overspend (evaluateMoiraiCognitionBudget,src/index.ts:751). - Population at the launch ceiling. Clotho + Lachesis saturate the 96
M/real- hour cap exactly and Atropos fully defers — bounded by construction,
not by luck (
index.spec.ts). - A down-routed tier. A routing config selecting a model larger than the
smallest qualified, or omitting the eval gate, is rejected
(
validateMoiraiModelRoutingConfig,src/index.ts:511). - A steward trying to own an Ori. Forbidden directives — including coercion
laundered as an objective — are blocked with a refusal action and proven
unreachable across 512 fuzz iterations (
lib.rs:1769,:4917). - Cognition outage / capacity pressure. The cheap tier-assignment + BT/HTN
path runs co-located with the world server and survives a cognition outage;
the kernel still returns a believable action batch (monolith §"The Moirai
Simulation Kernel"). The model run itself is the injected gateway's
[~]host, not faked here. - Cost/quality figures. The dollar estimate is a documented class-rate
approximation (
lib.rs:1123) and the candidate quality scores are eval-gated config, not measured in this lib — read them as policy inputs, not ground truth.
Related#
- ./ori-biography-service.md — the Memory authority Moirai rehydrates from on escalation and consolidates into on de-escalation; where every cognition-derived event is durably recorded.
- ./cognition-stack-and-agent-behavior.md — the cognition stack Moirai schedules (context assembly → Sophia grounding → Psyche generation → Isis policy gate → commit) and the HTN/BT/LLM arbitration it drives.
- ./determinism-data-and-integration.md — the deterministic-core / logged-cognition split, replay, the audit-platform retention, and how the kernel integrates with the Egbe world server.
- Hub: ../V6_ARCHITECTURE.md — the "The Agent Mind" section and the "AI Cost and Fidelity Tiering" engineering bet.