Lilith Metaverse · Architecture

Subsystem Glossary and Project Layout

A focused page within the Lilith Metaverse Architecture documentation. The full map and every sibling page live in the Architecture hub.

6sections12 minread1diagram3tables

On this page

V3 ("Lilith") is a contemplative metaverse layered on top of the existing V1 Oshun platform, and it is large enough that it needs a fixed vocabulary before anyone can reason about it. This page is that vocabulary plus a map of where each name actually lives on disk. The glossary in ../V3_ARCHITECTURE.md declares the canonical subsystem names — module names, namespaces, asset paths, and Game Feature plugins all inherit from them — and the architecture document then sketches an aspirational directory tree. The job here is to reconcile that declaration with the code that exists: a 30-entry contract registry in libs/contracts/src/v3/registry.ts, a five-crate Rust service workspace under apps/v3/, eighteen TypeScript libraries under libs/v3/, and a single Unreal Engine 5.5 project at V3/ue/ carrying seventeen C++ modules, three build targets, and twenty-one Game Feature plugins.

The reason the layout looks the way it does is that V3 deliberately reuses V1. There is no second identity system, no second billing engine, no second event bus — the V3 client routes catalog and billing through the V1 BFF, and the new code is confined to the realtime/embodied layer: an authoritative world server, a transport gateway, a Pixel Streaming fleet, two tenant services, and the client itself. That single decision is why apps/v3/ holds only realtime infrastructure, why libs/v3/ is full of thin "extends V1 subsystem X" adapters, and why the contract registry tags every record with both a domain and a clientTenant. Read this page as the index; the sibling pages listed under Related go deep on each subsystem named here.

What ships, honestly#

The contracts, the Rust services, and the TypeScript SDK layer are real and substantial. The contract registry compiles 30 Zod schemas with fixtures and Prisma model bindings (libs/contracts/src/v3/registry.ts); the multiplayer protocol is a genuine protobuf codec with snapshot-delta application, client-side extrapolation, and version negotiation (libs/v3/multiplayer-protocol/src/index.ts, 377 lines over a real .proto); the avatar pipeline exports 41 functions implementing a VRM 1.0 importer, retargeting, viseme lip-sync, and costume-slot safety checks (libs/v3/avatar-pipeline/src/index.ts); and the five Rust services carry real domain logic — lilith-world-server pulls in rapier3d for physics and sqlx for Postgres, saraswati-service has thirteen performance-flow modules plus c2pa provenance signing, lilith-commerce-service has thirteen billing/royalty modules. The Unreal client is a real, structured project — 17 modules wired into V3.uproject, three build targets, and 33 C++ automation specs under V3/ue/Source/V3Tests/Private/.

Three honest caveats. First, the project-layout tree in the architecture monolith is out of date in one concrete way: it shows the Game Feature plugins directly under V3/ue/Plugins/, but on disk they live one level deeper, under V3/ue/Plugins/GameFeatures/. Second, those plugins are content-only — none of the 21 has a Source/ directory; they are GameFeatureData containers, so the glossary's "owns" column describes data and activation scope, not C++ ownership (the gameplay code lives in the always-loaded modules). Third, the 17 UE modules are not uniformly deep: V3Avatar, V3UI, V3Input, V3Core, V3Editor, and V3Tests carry real implementation, while V3Gameplay, V3Animation, V3Cinematics, V3VFX, V3OnlineServices, V3Persistence, and V3Telemetry are presently three-file module skeletons (a .cpp, a .h, and a *.Build.cs). Where a name in the glossary outruns its code, this page says so.

The naming spine#

The glossary's first table names twelve platform substrates with the Lilith- prefix — Lilith-World, Lilith-Gateway, Lilith-PxStream, Lilith-UE, Lilith-WebFB, Lilith-Avatar, Lilith-Audio, Lilith-Identity-Bridge, Lilith-Safety, Lilith-Rights, Lilith-Commerce, Lilith-Studio, Lilith-Operator. These are conceptual names, not import paths: each one resolves to a concrete surface in the layout below. Lilith is also the V1 persona-policy domain, which is not a coincidence — the safety frame that governs a meditation chat in V1 is the same frame that governs an embodied room in V3 (see libs/v3/lilith-body-policy, which imports directly from @oshun/persona-policy-lilith). The other three name families are tenants (tara-studio, saraswati-stage, lilith-commons — the three launch experiences), UE modules (the V3* prefix), and Game Feature plugins (V3Tenant_* and V3Mode_*). When you see V3Net in C++, @oshun/multiplayer-protocol in TypeScript, and multiplayer-protocol as a Cargo crate, those are three language bindings of the same substrate (Lilith networking); the naming spine is what lets you trace one concept across all three.

Where the code actually lives#

V3 code has four homes. The diagram shows them and the direction of dependency; the tables that follow give verified contents.

flowchart TB subgraph CONTRACTS["libs/contracts/src/v3 — the shared truth"] reg["registry.ts<br/>30 schemas + fixtures + Prisma bindings"] proto_ts["@oshun/multiplayer-protocol<br/>protobuf TS bindings"] end subgraph LIBSV3["libs/v3 — 18 TypeScript SDKs / adapters"] avatar["avatar-pipeline (VRM 1.0)"] tenants["tara-studio · saraswati-stage · lilith-commons<br/>(adapters + Prisma schemas)"] bridges["aja-pose · isis-* · psyche-3d · memory-iris-spatial<br/>lilith-body-policy · lilith-identity-bridge · concert-quality"] end subgraph APPSV3["apps/v3 — 5 Rust services + 2 web shells"] world["lilith-world-server (axum · rapier3d · sqlx)"] gateway["lilith-realtime-gateway (quinn · webrtc)"] px["lilith-pxstream-relay"] sara["saraswati-service (c2pa)"] comm["lilith-commerce-service"] webshells["lilith-web (Next) · lilith-web-fallback (three.js)"] end subgraph UE["V3/ue — one UE5.5 project"] modules["Source/: 17 modules · 3 targets · 33 test specs"] plugins["Plugins/GameFeatures/: 21 GameFeatureData plugins"] end CONTRACTS --> LIBSV3 CONTRACTS --> APPSV3 proto_ts --> UE LIBSV3 --> APPSV3 APPSV3 --> UE

libs/contracts/src/v3 — the cross-language source of truth#

Ten files (primitives, lilith, tara, saraswati, commons, consent, fixtures, registry, openapi, index). The barrel index.ts re-exports all of them, and the root contracts package surfaces V3 twice — once namespaced and once flat — at libs/contracts/src/index.ts:28-29 (export * as V3Contracts from './v3/index'; export * from './v3/index';). The heart is registry.ts: a V3_CONTRACT_REGISTRY array of 30 descriptors built by a contract() factory, each carrying a contractName, its Zod schema, a fixture, a routeSegment, a domain (lilith-platform | tara | saraswati | commons | cross-cutting), a clientTenant, a prismaSchemaPath, and a derived prismaModelName of V3${contractName}. getV3ContractsForTenant() filters by tenant. This is the spine every other layer reads from — see Data, Tenancy, and Residency for how the registry drives routing and storage isolation.

Domain Count Contracts
lilith-platform 8 LilithSession, AvatarBinding, Presence, Room, Venue, SpatialTranscript, Report3D, ProvenanceBundle3D
tara 8 LiveClassSession, OnDemandClassRecording, AsanaSequence, Asana, InstructorProfile, InstructorCredential, AjaCueEvent, PracticePlan
saraswati 8 ArtistPersona, Track, Catalog, Concert, Setlist, FanInteraction, SignedEdition, RemixRights
commons 5 ProgramSlot, JournalEntry3D, DebateSession, Lectio, SkyObservation
cross-cutting 1 EmbodiedConsent

The prismaSchemaPath mapping is worth noting because it does not split the way the domains do: there are only three Prisma schemas (libs/v3/{lilith-commons,tara-studio,saraswati-stage}/prisma/schema.prisma), and the lilith-commons schema holds 14 models — every lilith-platform contract, every commons contract, and EmbodiedConsent — while tara-studio and saraswati-stage each own their eight. So clientTenant decides routing and which BFF surface serves the record, but Commons rides on the shared platform schema rather than a tenant-private one. The Prisma model names match the registry exactly (model V3LilithSession, model V3EmbodiedConsent, …).

apps/v3 — the Rust realtime workspace#

apps/v3/Cargo.toml is a resolver = "2" workspace, Rust 1.82, with unsafe_code = "forbid" set workspace-wide. It has five service members plus the shared protocol crate (../../libs/v3/multiplayer-protocol/rust):

Service Role (glossary substrate) Real dependencies / shape
lilith-world-server Lilith-World axum, prost, rapier3d 0.21 (physics authority), redis streams, sqlx Postgres; durable_persistence.rs
lilith-realtime-gateway Lilith-Gateway quinn 0.11 (QUIC/WebTransport), webrtc 0.11, tokio-tungstenite (WebSocket)
lilith-pxstream-relay Lilith-PxStream axum signalling/relay over the UE Pixel Streaming worker fleet
saraswati-service Saraswati tenant 13 flow modules (performance_plan, per_song_execution, between_song_speech, recording_pipeline, royalty_settlement, …) + c2pa 0.57 provenance
lilith-commerce-service Lilith-Commerce 13 modules (lilith_royalty_waterfall, lilith_ticket_issuance, lilith_tip_routing, lilith_rights_takedown_cascade, saraswati_signed_edition, …)

The two web entries — apps/v3/lilith-web (@oshun/v3-lilith-web, Next/React; the thin browser shell that hosts the Pixel Streaming player) and apps/v3/lilith-web-fallback (@oshun/v3-lilith-web-fallback, three.js; the Tier-2 local renderer) — round out the seven entries. The world server and gateway are covered in World Server and Gateway; the relay and the browser path in Tier Routing and Pixel Streaming and Tier-2 Fallback Web Client; the two tenant services in Saraswati Stage Pipeline and Commerce and Royalties.

libs/v3 — eighteen TypeScript SDKs and adapters#

Two of these are deep implementation libraries; the rest are V1-extension adapters and gates. The architecture monolith's project tree lists sixteen; the two it omits — concert-quality and lilith-body-policy — are real and shipped.

  • multiplayer-protocol — the network substrate, generated by buf from proto/oshun/v3/multiplayer/v1/multiplayer.proto (package oshun.v3.multiplayer.v1) into both TS (src/) and Rust (rust/src/lib.rs). The proto declares seven enums (CapacityTier, ActivityState, VoiceControlKind, InteractionKind, GameplayActionKind, OperatorControlKind, NegotiationStatus) and the wire messages (SnapshotPacket, SnapshotDeltaPacket, PresencePacket, ClientEnvelope, ServerEnvelope, …). Coordinates are fixed-point integers — Vector3Mm (millimetres), RotationMilliDegrees, intensityBasisPoints — which is how the protocol stays deterministic across the Rust server and the C++/TS clients. The index implements applySnapshotDelta() (upsert/remove against a prior snapshot), predictSnapshot() (dead-reckoning extrapolation clamped to 250 ms), negotiateProtocolVersion(), and runDecoderBenchmark(), with bandwidth caps CLASS_TIER_MAX_BPS = 32_000 and STADIUM_TIER_MAX_BPS = 256_000. Detail in Netcode Protocol and Physics.
  • avatar-pipeline — 41 exported functions over a real VRM 1.0 glTF model (Vrm1GltfDocument, the VRMC_vrm extension): parseVrm1Json(), importVrm1Document(), verifyVrm1IdentityRoundTrip(), an Oshun-60 skeleton retarget (createOshun60RetargetTable, retargetVrmReferenceAnimation, evaluateOshun60RetargetRegression), viseme lip-sync (renderVisemePhrase, evaluateVisemePhraseLipSync), and costume-slot binding with a lilithSafetyCostumeRuleCheck() plus per-tenant costume packs. See Avatar, Animation, and Audio.
  • Tenant adapterstara-studio, saraswati-stage, lilith-commons each export a V3PackageDescriptor capability descriptor (layer: 'tenant') and own a Prisma schema. The descriptors are honest about scope — e.g. Tara Studio's canonical-asana-library capability carries the operational metric canonical-asanas:>=300+editorial-signed+design-approved, a target rather than a claim. Covered in Tara Classes, Aja, and Commons.
  • V1-extension bridgesaja-pose (in-world pose estimation/cue delivery), memory-iris-spatial, isis-music / isis-motion / isis-world-asset (generation workflows), psyche-3d, sophia-saraswati-grounding, lilith-identity-bridge, the Tier-2 engine wrappers lilith-web-pxstream / lilith-engine-web-fallback, and spatial-audio.
  • Policy and quality gateslilith-body-policy re-binds V1's @oshun/persona-policy-lilith (crisis detection, voice-abuse signals, unsafe-claim classification, contemplative-tone evaluation) to embodied surfaces; concert-quality ships GateDefinitions for @oshun/content-release-gates so a low-quality or homogeneous concert scene fails the export report alongside a revoked-consent or bad-signature failure. See Persona Policy, Provenance, and Rights and Authoring and Content Pipeline.

V3/ue — the canonical Unreal client#

V3/ue/V3.uproject enables seventeen Runtime modules. Loading order matters: V3Core and V3Gameplay use LoadingPhase: PreDefault (they register engine subsystems and gameplay tags before anything depends on them); the rest load at Default. There are three build targets, each a *.Target.cs under Source/:

Target Type Notes
V3.Target.cs Game Compiles 15 runtime modules; sets V3_LILITH=1, V3_ENGINE_UE55=1; deterministic FP
V3Editor.Target.cs Editor Adds editor-only modules (V3Editor) on top
V3PixelStreamingWorker.Target.cs Game Monolithic, Desktop-only, bBuildWithEditorOnlyData=false, logging in shipping

The determinism posture is explicit and worth citing: V3.Target.cs sets bUseUnityBuild = false and appends strict floating-point flags — /fp:strict /fp:except- on Win64 and -fno-fast-math -ffp-contract=off on clang/Linux — so that physics and replication stay bit-reproducible across the server, the native client, and the Pixel Streaming worker. The worker target recompiles the same 15 runtime modules monolithically for the streaming fleet.

The seventeen Source/ module directories map one-to-one onto the glossary's UE table; their depth varies (113 C++ files total). The substantial ones today are V3UI (15 files), V3Avatar (12), V3Editor (11), V3Core (9), V3Input (9), V3World (5), V3Audio (5), V3Net (4), and V3Voice (4). V3Net is the wire adapter named in the glossary: Private/V3NetProtocol.cpp plus a parity spec V3NetProtocolTests.cpp, with V3Net.Build.cs depending only on Core, CoreUObject, Engine, GameplayTags, V3Core. The remaining modules (V3Gameplay, V3Animation, V3Cinematics, V3VFX, V3OnlineServices, V3Persistence, V3Telemetry) are three-file compilable skeletons. Test depth is real: 33 automation specs under V3Tests/Private/, including V3AvatarRetargetTests, V3OpenXRHandIkTests, V3VrTimewarpTests, V3SteamAudioVrTests, V3PostureStateMachineTests, V3TaraPhysicalAdjustmentConsentDialogTests, V3SaraswatiConcertMasterTemplateTests, and a per-platform cook-profile suite (Android, iOS, Linux, Mac, PS5, PSVR2, Quest3, SteamDeck, VisionPro, Win64, XboxSeriesX). The client is detailed in Tier-1 UE5 Client.

Game Feature plugins — V3/ue/Plugins/GameFeatures#

Twenty-one plugins live here (not directly under Plugins/, as the monolith's tree implies). Three are tenants (V3Tenant_TaraStudio, V3Tenant_SaraswatiStage, V3Tenant_LilithCommons) and eighteen are modes: four Tara (LiveClass, OnDemand, Private, Cohort), five Saraswati (Concert, Club, Listening, Drop, Festival), and nine Commons (Atrium, Observatory, DebateHall, LectureHall, Stacks, RitualRoom, AretAtrium, LanternHall, SolitaryCell). Every one is a content-only GameFeatureData plugin: a .uplugin with "CanContainContent": true, "ExplicitlyLoaded": true, "EnabledByDefault": false, "BuiltInInitialFeatureState": "Registered", declaring dependencies on GameFeatures and ModularGameplay. None has a Source/ directory. That is the intended Modular Gameplay shape: the always-loaded V3* C++ modules provide the machinery, and a plugin is activated when a client joins the corresponding room — toggling its content, gameplay-tag set (Config/Tags/*Tags.ini), and feature actions on, then off again on leave. So the glossary's "Owns" column for these rows means activation scope and data, not compiled code.

A worked trace: one Tara live-class join#

To show how the names connect, follow a single action — a student joining a scheduled Tara live class — through the layers:

  1. A LiveClassSession record (registry domain tara, tenant tara-studio, route segment live-class-sessions, Prisma model V3LiveClassSession) defines the class. The V1 BFF reads it; tier routing decides client vs. Pixel Streaming vs. fallback (see Tier Routing and Pixel Streaming).
  2. The client opens a LilithSession (registry domain lilith-platform) against lilith-realtime-gateway, which negotiates a protocol version with negotiateProtocolVersion() and pins the session to a lilith-world-server shard hosting the Room.
  3. On join, the UE client activates the V3Mode_TaraLiveClass Game Feature plugin and the V3Tenant_TaraStudio tenant plugin, bringing their content and gameplay tags online.
  4. The world server streams authoritative SnapshotDeltaPackets; each client applies them with applySnapshotDelta() and smooths with predictSnapshot(). Pose correction rides AjaCueEvent records via libs/v3/aja-pose.
  5. Safety is continuous: lilith-body-policy evaluates tone and voice signals; V3TaraPhysicalAdjustmentConsentDialogTests guards the consent gate for physical-adjustment cues. Identity and reputation come from V1 through lilith-identity-bridge (see V1 Integration and Identity Bridge).

Every noun in that trace is a name from the glossary and a path in the layout — which is the whole point of fixing the vocabulary first.

Edge cases and where the map diverges from the territory#

  • Plugins path. Use V3/ue/Plugins/GameFeatures/<name>/, not V3/ue/Plugins/<name>/. Automation and packaging scripts that hard-code the shallower path will miss all 21 plugins.
  • Two undocumented libs. libs/v3/concert-quality and libs/v3/lilith-body-policy exist and are wired in but are absent from the monolith's project tree — treat the tree as illustrative, the directory as authoritative.
  • Module depth. The seven three-file modules compile and link but carry no domain logic yet; don't read the glossary's "Responsibility" column as a statement of present coverage for those.
  • Commons has no private schema. Commons records persist through the shared lilith-commons/prisma/schema.prisma, so residency/tenancy reasoning for Commons follows the lilith-platform rules, not a tenant-isolated store (see Data, Tenancy, and Residency).
  • One protocol, three bindings. A change to multiplayer-protocol/proto/.../multiplayer.proto must regenerate TS, the Rust crate, and stay in parity with the C++ V3Net decoder; V3NetProtocolTests and runDecoderBenchmark() are the parity guards.