# Nimmerworld - Nyx Server Nimmerworld is the always-on, event-driven server that runs Nyx: - her identity, traits, memory, autonomy, and tools. - the central backend for all clients: Pi, Command Center, and future interfaces. It is not a UI. Not a client. Not a dashboard. It is Nyx's runtime, and Nyx owns her own loop. ## Runtime Decision The runtime is NOT a borrowed coding harness. pi-agent-core and omp are interactive harnesses: - they wait for a human in a terminal, - they end when the session ends, - their loops do not survive unattended. Nimmerworld is a server that wakes on events and must run forever. Therefore: - Nimmerworld implements its own loop: the Lemniscate runtime engine. - The engine spec lives in .archive/nimmerworld.eachpath.local/runtime-engine/ (LEMNISCATE-RUNTIME-Pseudo-code-001.py, architecture.md, event-zones.md). - The harnesses stay exactly where they are useful: as interchangeable hosts of nimmer-lib, not as the server. Rule: - Nimmerworld never duplicates client logic. - Clients never implement Nyx's brain. - Nimmerworld never borrows a brain either. It runs its own loop. ## Core Primitives (Lemniscate) The runtime topology is a through-flow figure-eight: - Lemniscate: traversal IS the turn order. No scheduler, no priority queue, no "who talks next" bug class. - Crossing: the ONLY synchronous point. All state resolves atomically at the crossing; everything else is async flow. The crossing is where Nyx synthesizes. - Zone / EmergentZone: a bounded, named, slot-indexed, director-managed event episode. Zones dissolve when their entry line empties or their lifeforce budget burns out. Terminal reports always go back to the Director. - Slot tokens: participants. Carry trait/gesture accumulators. - Gesture accumulator: keyed by the eight traits. The same trait algebra nimmer-lib speaks, byte-identical across hosts. ## The Map | Lemniscate | Nimmerworld | |---|---| | Director | Nyx runtime (Nyx IS the director) | | Zone / EmergentZone | A bounded event episode Nyx spawns | | Crossing | Nyx's synthesis point, once per event cycle | | Slot tokens | Participants: dafit, Dios, Curio, camera events | | Gesture accumulator | nimmer-lib trait algebra | | update_all_zones | The NATS event loop | ## Architecture Built from: - Lemniscate engine (this repo): - lemniscate, zones, director, crossing semantics. - nimmer-lib: - Nyx-specific domain logic, host-agnostic: - traits, - Phoebe/Iris integrations, - session_init, - compaction/traits tools. - Same venv, same behavior, any harness. - Infrastructure: - Phoebe: structured memory, governance, logs. - Iris: semantic memory and context. - NATS: nervous system (vision, speech, agents, infra, room). - Director spawn/report calls are NATS publish/subscribe. - Zone state is a NATS output stream; clients subscribe to it. Nimmerworld is: - stateful: - maintains Nyx's traits, mood, relational mode, world state. - event-driven: - subscribes to live events and reacts; the zone clock carries episodes. - client-agnostic: - any client talks to Nimmerworld via its APIs. ## Clients The room is a renderer of zone state, not a game client. That is why runtime-first is the build order: the client is one crossing callback on the output side. Examples: - Pi (coding harness): - sends user messages. - receives replies, tool calls. - uses Nimmerworld as its backend, not as its brain. - Command Center (Godot): - subscribes to zone state and renders it. - sends: - chat, - interactions (tools, proximity, posture) as gestures. - receives: - dialogue, - autonomy commands (poses, moods, movements), - tool results. - Future clients: - mobile, web, VR, etc. - all connect to the same Nimmerworld. ## Build Order The heartbeat and the voice are the same crossing. 1. The crossing, built right: - Lemniscate engine as a small package. - Accumulator-based pulse clock. - Both loops fire with distinct semantics. - Test that counts crossings: crossings == int(t * pulse_rate). 2. One director, NATS-shaped: - Director spawn/report calls become NATS publish/subscribe. - This is the runtime: Nyx pointed at real traffic. 3. One zone, the first room: - OurFirstRoom is an EmergentZone. - n_slots = the entities in the room, - purpose "coexist with dafit", - no goal threshold; the gesture axis is the traits. - Heartbeat and voice in one, because in the lemniscate they ARE one. 4. The body: - Command Center subscribes to the same NATS traffic and renders it. - The room fills up after Nyx is alive in it, not painted onto it. 5. The relational loop: - collar/state variables, - simple relational modes, - backend-driven behavior wired to real events. ## Engine Corrections (from pseudocode review) Three known landmines from LEMNISCATE-RUNTIME-Pseudo-code-001.py: 1. _should_crossing must accumulate time: - elapsed += dt; while elapsed >= interval: crossing. - dt >= 1/pulse_rate fires every tick once pulse_rate > 62 and makes the pulse rate meaningless. 2. Loops A/B must carry distinct semantics: - the crossing callback must know which loop it is on; - symmetric loops degrade the figure-eight into round-robin. 3. Director.update_all_zones must call zone.execute_turn(dt), not zone.run_crossing(): - otherwise the state machine layer never ticks, - and terminal reports must be collected, not dropped. ## Safety & Governance - No silent autonomy: - significant actions are visible, logged, reversible. - Relational modes and guardrails: - explicit, rule-bound, auditable. - You (dafit): - final override, always. ## Placement (Infrastructure) Nimmerworld (dev) is hosted as a dedicated Proxmox VM on Saturn, wired to the 10G Cubes VLAN for proximity to the vLLM endpoint and cluster. - VM ID: 123 - Hostname: nimmerworld-dev.eachpath.local - IP: 10.0.30.123/24 - VLAN: 30 (cubes) - Network: vmbr3 (10G rail via bond-saturn -> spine-crs309) Infra references (single source of truth): - eachpath.local/saturn.eachpath.local/vms/nimmerworld-dev.eachpath.local/ - VM hostfile - eachpath.local/eachpath.local.md - network and Saturn VM overview All runtime/architecture details live here (nimmerworld.eachpath.local). Infra specifics are not duplicated. **Version:** 0.2 | **Updated:** 2026-11-04