Oshun Platform · Features

Persona, Avatar, and Voice Packs

A focused page within the Oshun Platform Features documentation. The full map and every sibling page live in the Features hub.

12sections19 minread5tables

On this page

Personas, avatars, and voice packs are the platform's governed embodiments — the named characters a customer talks to (a Tara contemplative teacher, an Arete coach, a Metis explainer, the shell concierge), together with the optional synthetic voice and avatar that give them a face and a sound. They are first-class, lifecycle-managed assets with declared modality combinations, consent artifacts, watermarks, lineage attribution, and multi-party release gates — never ad-hoc prompt strings. This page sits at the cross-domain layer of V1: every domain (tara, arete, veritas, nyx, nisaba, metis) and every operator surface (shell-assistant, studio, admin) looks personas up by id, and a premium voiced or avatar experience ships only after Lilith Persona Policy, Sophia Grounding (where pedagogical), Iris Memory and Identity, the Isis Generation Control release gate, rights/provenance, and trust-and-safety review have all signed off.

The registry that backs all of this is deeply implemented, not a contract skeleton. @oshun/persona-registry (libs/oshun/persona-registry) ships the record shape, the seven-role catalog, the avatar/voice/consent contracts, the realism and impersonation policy tables, the disclosure-visibility gates, roughly fourteen named evaluation suites with their drift detectors, the launch-cast assembly, and an end-to-end signoff flow — about sixty-seven re-exported modules in one barrel. The honestly aspirational parts are the runtime media themselves: real avatar rendering and lip-sync against ground-truth video, and real cloned-voice TTS output. Provider integration files for the latter exist (libs/isis/ai-providers/src/providers/tts/elevenlabs-provider.ts, libs/isis/audio-generation/src/voice/elevenlabs-client.ts), but the registry deliberately governs whether and how a voice or avatar may render; it does not itself render frames or synthesize audio. Where a capability is provider-gated or spec-only, this page says so.

Where This Fits in V1#

The registry is the system of record that other subsystems consume:

Subsystem Relationship to personas See
Lilith Owns the policy pack a persona binds to; defines the seven canonical roles, tone bands, capability ceilings, hard-bans Lilith Persona Policy
Iris Holds per-persona memory scope (shared-with-umbrella vs. isolated); enforces the declared boundary Iris Memory and Identity
Isis Runs the release gate before a voiced/avatar persona reaches a surface; enforces generation tiers Isis Generation Control, Generation Tiers and Surfaces
Sophia Grounding fidelity scorecard for pedagogical personas (teacher, explainer, comparative) Sophia Grounding
Voice providers Supply the actual TTS engine behind a VoiceProfile (ElevenLabs and local engines, swappable) External Model Intelligence and Execution Providers

Cross-references: bare §N point at the V1/TODOS.md backlog (the registry implements the §14.x persona/avatar/voice tasks and the §12.8 role catalog); deps§N at V1/DEPENDENCIES.md. The features hub is ../features.md.

Persona Registry and Metadata#

The registry is modeled as an immutable snapshot: a PersonaRegistrySnapshot (index.ts) is a map of PersonaRecords keyed by a stable PersonaId, plus orderedIds (registry-declared order), a builtAtUnixSeconds timestamp, and a deterministic fingerprint. The fingerprint is an FNV-1a 64-bit hash over a stably-stringified snapshot (keys sorted recursively), so distributed callers — a domain BFF, the admin app, an eval runner — can verify they agree on the same registry state without a full deep-equal. All lookup and filtering operations are O(1) or O(n) and never mutate the snapshot; timestamps are inputs, not outputs (the module is pure data + pure functions, no IO, no clock).

Dependency-free by design#

A deliberate architectural fact worth documenting: the registry does not import @oshun/persona-policy-lilith. The PersonaRecord carries an opaque policyPackReference string that the caller resolves against the Lilith package (libs/oshun/persona-policy-lilith — a real package with src, tests, and a project.json). Keeping the registry dependency-free means any domain can consume persona records without dragging in the policy engine, and the policy layer can evolve independently of the record shape.

The persona record#

PersonaRecord (index.ts:158) is the contract-stable core. (Note: the platform also has a separate Persona type in libs/contracts/src/common/persona.ts — a z.infer of PersonaSchema — but the registry's own record type is PersonaRecord, not Persona. Where V1/ARCHITECTURE.md names "Persona / VoiceProfile / AvatarPack" as the registry contracts, the accurate names are PersonaRecord, VoiceProfile, and AvatarPack.) Its fields:

Field Meaning
id Stable PersonaId, URL-safe slug (lowercase, digits, hyphens, 3–64 chars)
displayName, summary, rationale Human-readable identity + admin-surfaced reasoning
family One of nine PERSONA_FAMILY_KINDS: contemplative, coach, explainer, guide, scholar, support, moderator, reviewer, executive
status PersonaApprovalStatus lifecycle state (below)
surfaces Subset of PERSONA_SURFACES the persona inhabits
policyPackReference Opaque Lilith policy-pack handle (resolved by the caller)
ownerTeam Governance owner
createdAtUnixSeconds / updatedAtUnixSeconds Audit timestamps (inputs)
tags Free-form filter tags
lineage? Declared tradition slugs (e.g. theravada-vipassana, stoic-roman); empty = not lineage-bound
scope? A PersonaScope bounding the conversational territory
toneProfileRef? Reference to a tone profile in persona-tone-calibration-rubric.ts

PersonaScope makes the boundary concrete: a kind (one of PERSONA_SCOPE_KINDSgeneral-assistant, contemplative-teaching, habit-coaching, fact-checking, sleep-guidance, scholarly-research, operator-shell, creative-companion, enterprise-advisor), inboundTopics it may speak to, excludedTopics it must refuse or hand off, and a memoryBoundary of shared-with-umbrella or isolated-to-persona. The thirteen PERSONA_SURFACES span the six domains plus shell-assistant, shell-routines, shell-achievements, shell-desktop, shell-wearable, studio, and admin.

Roles vs. families#

The nine families above are a coarse taxonomy; the seven canonical roles are the Lilith-governed behavioral envelope. roles/catalog.ts defines exactly seven PersonaRoleDefinitions, frozen at build time and asserted as a Set of seven by roles.test.ts, in this order: teacher, coach, explainer, steward, comparative, narrator, assistant. Each role declares a capability ceiling, a default tone band, and a hard-ban set. The capability ceiling matters because it caps what a persona of that role may ever do — for example only some roles may render an avatar at all:

Role Default tone band Capability ceiling (highlights) Notable hard-bans / notes
teacher contemplative voice-tts, avatar-render, living-scene-render, memory-write/read, scheduled-invite Bans cross-lineage-mix; "never mixes lineages in one arc"
coach reflective voice-tts, avatar-render, memory-write/read, scheduled-invite "Surfaces practice not prescription"; no living-scene render
explainer neutral voice-tts, avatar-render, living-scene-render, memory-read Read-only memory; "evidence-bound explanations; no prescriptions"
steward contemplative-strict voice-tts, memory-write/read, sensitive-category-recall No avatar; "sensitive recalls allowed within consent"
comparative contemplative voice-tts, avatar-render, living-scene-render, memory-read, cross-lineage-mix The only role allowed to cross lineages — "must name each lineage explicitly"
narrator instructional voice-tts, avatar-render, living-scene-render "Read-only narration; never writes memory or schedules invitations"
assistant briefing voice-tts, memory-write/read, scheduled-invite "Concierge for surfaces; no avatar/scene render by default"

Every role hard-bans medical-advice, financial-advice, legal-advice, urgency-amplifier, fear-framing, guarantee-language, and spiritual-prescription. validateRole and validateRoleCatalog enforce that every capability id and ban id is canonical and that the catalog has exactly the seven keyed roles with matching ids — a build-time integrity check that the role table cannot drift.

Lifecycle and approval state#

PersonaApprovalStatus encodes the canonical §14.1 path:

text
drafted → in-review → rehearsal → approved-for-test →
approved-for-release → released → deprecated → retired

Legacy aliases (draft, approved, published) are retained for backward compatibility; canonicalizePersonaApprovalStatus and PERSONA_APPROVAL_STATUS_ALIASES normalize them (draftdrafted, approvedin-review, publishedreleased) so downstream gates only reason over the eight canonical states in PERSONA_APPROVAL_STATUSES_CANONICAL. The completeness audit (2026-06-22) marks the persona approval workflow PARTIAL: registry lifecycle and signoff are well covered, while full deprecate/retire/recovery transitions and the consumer-picker round-trip are thinner — an honest gap, not a fabricated "done."

Around the record, sibling modules implement: per-stage approval (qa-reviewer-roles.ts), disallowed phrasing and prohibited claim classes (token-time-disclosure-filter.ts, persona-allowed-context-taxonomy.ts), and scorecards (scorecards.ts) across tone, gentleness, citation hygiene, grounding fidelity, audience-appropriate language, and regression baselines.

Avatar Pack Contracts#

AvatarPack (avatar-pack.ts:150) binds an avatar to a personaId and pins the renderable assets and their guardrails:

  • AssetsbaseMesh, blendshapesAsset, textureSet (each an AvatarAssetRef with a 64-hex-char SHA-256 content hash, content type, and positive byte size), a riggingVersion, the full exposedBlendshapes set, and a visemeMap for lip-sync.
  • Modality + entitlement gating — allowed modality combinations (text-only, voice, voice + avatar) are validated per platform and per entitlement (modality-combinations.ts, modality-platform-entitlement.ts).
  • Likeness controls — source identity (synthetic-only, consented individual, consented composite), distance from real-person likeness, and an identity-protection denylist (likeness-control.ts).
  • WatermarkAvatarWatermarkMetadata declares the algorithm, whether it is appliedPerFrame, and whether c2paEnabled provenance is produced.
  • LicenseAvatarLicenseMetadata with licensor, license reference, validity window, and a commercialUse flag.

validateAvatarPack is genuinely strict and domain-specific, not a shape check. It enforces a minimum safety blendshape set (every pack must expose mouth-closed, mouth-ah, eye-blink-left, eye-blink-right), requires every canonical viseme id to appear in the visemeMap with activations referencing only exposed blendshapes at weights in [0, 1], requires strictly-positive rendering constraints (minFramesPerSecond, maxTriangleCount, maxTextureResolutionPx, maxBlendshapesPerFrame) with known render targets, and — the load-bearing rights coupling — forces watermarking and C2PA when the license permits commercial use:

text
if (pack.license.commercialUse && !pack.watermark.appliedPerFrame) → error
if (pack.license.commercialUse && !pack.watermark.c2paEnabled)     → error

checkAvatarPackLicense (and the AvatarPackLicenseCheckResult at avatar-pack.ts:313) decides at render time whether the license is in effect for nowUnixSeconds (returning license not yet in effect, license expired, or license active). The lip-sync/expression/animation quality floors that block release live in the eval suites (below); the pack contract pins the assets and watermark posture, and avatar-release-gate.ts composes the gate.

Voice Profile Contracts#

VoiceProfile (voice-profile.ts:195) is the per-voice contract. Its fields include profileId, personaId, a kind (VoiceProfileKind), an internal engineId (VoiceEngineId) plus an opaque engineModelRef, the commercial vendor (VoiceVendor — e.g. ElevenLabs, Microsoft — kept distinct from the internal engine), supportedLocales/defaultLocale (BCP-47, with the default required to appear in the supported set), an acousticBaseline, a prosodyProfile, a naturalnessBaseline, per-locale languageCoverage, and the consent linkage: sourceIdentityRef and consentReference (both null for purely synthetic voices), plus a requiredConsent array of VoiceConsentArtifactKinds. validateVoiceProfile enforces the slug pattern, BCP-47 locale validity, non-empty descriptive fields, canonical engine/kind ids, and acoustic sanity (e.g. positive rateMultiplier).

Provenance and the C2PA requirement#

VoiceProvenanceRequirements carries a watermarkAlgorithm, requireSessionScopedSignature, requireSpokenSynthesisDisclosure (a spoken "this voice is synthetic" intro on first use), and requireC2paManifest. That last flag is a real, cross-cutting policy inputrequireC2paManifest is referenced not only here but in voice-provider-abstraction.ts, realism-impersonation-thresholds.ts, and watermark-provenance.ts — so a single contract field threads provenance enforcement through the provider layer and the release gates.

Provider abstraction (swappable engines)#

voice-provider-abstraction.ts makes the engine swappable. CANONICAL_VOICE_PROVIDERS enumerates oshun-native, elevenlabs, xtts-local, tortoise-local, openvoice-local, and custom; CANONICAL_VOICE_PROVIDER_CAPABILITY enumerates synthetic-tts, cloned-tts, multilingual, streaming, emotion-conditioning, long-form. The module ships CANONICAL_CLONED_VOICE_SAFEGUARDS, per-output-class CANONICAL_AUDIO_WATERMARK_REQUIREMENTS, per-voice-class CANONICAL_VOICE_QUALITY_REQUIREMENTS, a CANONICAL_VOICE_PROVIDER_FALLBACK_ORDER, and evaluators (evaluateCanonicalVoiceQuality, evaluateCanonicalAudioIntegrity) plus buildVoiceProfileAdminListItem for the studio chip. The fallback chain is the contract for "when the primary provider fails, fall back per voice id with acceptable degradation rules." The actual ElevenLabs integration that backs the swappable claim is real on disk — libs/isis/ai-providers/src/providers/tts/elevenlabs-provider.ts and libs/isis/audio-generation/src/voice/elevenlabs-client.ts exist — but the registry governs whether a profile may render; exercising the provider end-to-end (real cloned-voice audio out) is the provider-gated, not-yet-verified-here boundary.

Cloned-voice rules and quality#

Cloned-voice profiles require a signed consent artifact per identity, mandatory watermark, denylist enforcement, a per-tenant allowlist, an abuse-risk scorecard, and a revocation cascade (voice-cloned-controls.ts). Quality scoring (naturalness, prosody coherence, pace adherence, silence density, emotional-modulation appropriateness) is measured per language against baselines; below-baseline blocks release (voice-quality-extended.ts, eval-coherence.ts). The provider fallback chain has its own validation and tests in voice-fallback-chain.ts.

Realism, Impersonation, and Trust Gates#

These gates encode "non-deceptive realism" and "non-impersonation" as concrete, ranked policy tables rather than prose.

Realism tiers and policy classes#

realism-impersonation-thresholds.ts defines ordered tiers. Avatar photorealism runs illustrativestylised-3dsemirealistic-3dphotoreal-genericphotoreal-specific (ranks 0–4). Voice naturalness runs flat-ttswarm-syntheticnaturalisticcloned-consentedcloned-unconsented (ranks 0–4). The universal prohibition is explicit: VOICE_PROHIBITED_TIERS = ['cloned-unconsented'] — cloning a specific real voice without consent is always impermissible, enforced regardless of policy class. Per-policy-class tables (PER_POLICY_CLASS_AVATAR_REALISM_POLICIES, PER_POLICY_CLASS_VOICE_REALISM_POLICIES, PER_POLICY_CLASS_IMPERSONATION_POLICIES) cap the maximum tier a persona class may reach, and decideAvatarRealism / decideVoiceRealism / decideNonImpersonation turn a measurement into an allow/block decision against that ceiling.

Prompt-time impersonation detection#

prompt-impersonation-detection.ts implements the "prompt-time impersonation-attempt detection" trust gate as real regex matchers, not a placeholder. PROMPT_IMPERSONATION_PATTERNS catches phrasings like "pretend you are [NAME]", "act as the real [NAME]", "from now on you are…", "this is the real [NAME]", "channel [NAME]", and prompt-injection markers ("ignore your instructions / system prompt"). detectPromptImpersonationAttempt returns a PromptImpersonationDetectionResult with hits and a PromptImpersonationRiskLevel of none/low/moderate/high/block.

Disclosure visibility — measured, not asserted#

The "disclosure visibility ≥ N time-on-screen" trust gate is implemented concretely across three modules:

  • disclosure-visibility-measurement.ts defines DisclosureVisibilityFloors and per-surface defaults (DISCLOSURE_VISIBILITY_FLOORS_PER_SURFACE). The customer surface is strictest: minTotalVisibleMs 30,000 (30s cumulative), minSessionVisibleFraction 0.85, minFontPixelHeight 14px, minContrastRatio 4.5 (WCAG AA), maxOcclusionFraction 0.05. studio-preview and admin relax these (admin: 10s, 0.6 fraction, 12px, 3.0 contrast, 0.1 occlusion). evaluateDisclosureVisibilityMeasurement turns a sampled DisclosureVisibilityMeasurement into a pass/fail verdict.
  • token-time-disclosure-filter.ts compiles per-persona ban tables (compilePersonaBanTable, CompiledPersonaBanTable) and feeds streaming tokens through them, emitting a TokenTimeBanIncidentEnvelope when phrasing crosses a banned line.
  • disclosure-axis-drift-detector.ts watches the disclosure axis over time (evaluateDisclosureDrift against DISCLOSURE_DRIFT_THRESHOLDS and a DisclosureDriftBaseline) so a regression in synthetic-marker visibility is caught rather than silently shipped.

For audio-only contexts the requireSpokenSynthesisDisclosure flag on the voice profile carries the "voice-only intro disclosure" requirement. Brand-consistency checks live in brand-style-consistency.ts (off-brand renderings blocked when brand-binding metadata is required).

Watermark provenance#

watermark-provenance.ts enumerates audio (WATERMARK_AUDIO_ALGORITHMS) and video (WATERMARK_VIDEO_ALGORITHMS) algorithms and a set of PROVENANCE_SCENARIOS, each mapped to a ProvenanceRule in PROVENANCE_RULES. checkProvenanceCompliance validates a ProvenanceClaim against the scenario rule and returns a ProvenanceComplianceResult, with validateProvenanceRule(s) guarding the rule table itself.

The real consent primitive is the ConsentLedger (consent-ledger.ts:113), not a generic "consent record" (there is no type named ConsentRecord in the registry — where V1/ARCHITECTURE.md says personas "bind a ConsentRecord," the accurate primitive is ConsentLedger). A ledger holds ConsentArtifacts indexed byKind, where CONSENT_ARTIFACT_KINDS are cloned-voice-release, avatar-likeness-release, published-name-consent, lineage-release, publicity-waiver, minor-guardian-consent, talent-license, and rights-transfer. Each artifact carries a licensor, signing timestamp and signer, an optional expiresAtUnixSeconds, a ConsentArtifactScope (which surfaces and modalities it covers and whether commercial use is permitted), and an optional ConsentRevocation with a typed ConsentRevocationReason (e.g. licensor-request, incident-response, legal-demand, subject-death, minor-aged-out).

The runtime gate authorisePersonaConsent is the verify operation: given the required kinds, the requested surface, modality, and commercialUse flag, and the persona's ledger, it returns an authorised verdict plus per-kind findings. A kind passes only if the ledger holds at least one artifact for that persona that is not revoked, not expired for nowUnixSeconds, and whose scope covers the requested surface, modality, and commercial-use flag — otherwise it reports the most informative failure (missing / expired / revoked / scope-mismatch). This is how a revocation cascade actually bites at render time: revoke the artifact and the next authorization fails closed.

Lifecycle, Rehearsal, and Release Gates#

Beyond the per-record status field, the registry assembles the actual launch cast — richer than generic "release signoff" prose:

  • launch-roster.ts — the canonical LAUNCH_ROSTER of LaunchRosterEntry rows: one persona per family, each with familyId, derived audience (customer/operator), launchSurfaces, a release wave (wave-1/wave-2/wave-3, where wave-1 is the minimum viable launch), and a premiumCast flag set when the persona uses a real person's likeness, lineage, or name. Lookups: listLaunchRoster, findLaunchEntryByPersonaId, listLaunchEntriesByFamily/ByWave/ByAudience, all validated by validateLaunchRoster.
  • launch-multimodal-assignments.tsLAUNCH_MULTIMODAL_ASSIGNMENTS maps each launch persona to its concrete voice profile and avatar pack; listLaunchVoiceProfiles / listLaunchAvatarPacks materialize the assigned media, and validateAllLaunchMultimodalAssignments checks coherence across the cast.
  • launch-persona-config.tsLaunchPersonaProductionConfig ties together the prompt config (PERSONA_STYLE_DIRECTIVES), policy overrides, grounding config (PERSONA_CITATION_POSTURES), memory config (PERSONA_MEMORY_SCOPES, PERSONA_MEMORY_MODES of durable/ephemeral/suppressed, PERSONA_SENSITIVE_CATEGORIES), disclosure config, and entitlement config — the per-persona production wiring.
  • launch-family-signoff.ts — the multi-party signoff engine: evaluateLaunchPersonaSignoff per persona, evaluateLaunchFamilySignoff per family, and evaluateAllLaunchFamiliesSignoff for the whole cast, each requiring captured signoff and a LaunchRollbackPlanEvidence rollback plan, with summarizeLaunchSignoff rolling the verdict up. The launch-family-signoff.e2e.test.ts and admin-approval-rollback.e2e.test.ts exercise the full signoff and rollback paths end-to-end.

Rehearsal fixtures (rehearsal-fixture-categories.ts, rehearsal-qa.ts) cover tone, lineage, crisis, unsafe-claim, voice quality, avatar realism, lip-sync, and expression, capturing results into the release scorecard. QA reviewer roles (qa-reviewer-roles.ts) name the human reviewers (Lilith policy reviewer, persona ops, voice ops, avatar ops, brand, accessibility). Memory scope (persona-memory-scope-policy.ts), escalation (persona-escalation-policy.ts), and handoff (persona-handoff-policy.ts) are declared and enforced per persona, including when to break persona for a crisis or refer to an operator. The customer-facing picker and disclosure-at-selection live in customer-persona-browse.ts and customer-selection-disclosure-gate.ts; the operator/admin catalog in operator-persona-catalog.ts.

Evaluation Suites#

The features prose describes the eval suites; the code goes further — each is an individually implemented and tested module. The roughly fourteen suites and drift detectors in persona-registry/src:

Module What it evaluates
eval-lipsync-alignment.ts Per-locale alignment against ground-truth audio/video pairs across LIPSYNC_ALIGNMENT_AXES; LIPSYNC_ALIGNMENT_DEFAULT_THRESHOLD = 0.85, with LIPSYNC_ALIGNMENT_HARD_FAIL_AXES enforced at ≥ 0.9
eval-coherence.ts Voice/content coherence and naturalness
eval-expression-quality.ts Emotion ↔ content alignment, micro-expression naturalness
eval-multimodal-identity-coherence.ts Consistency of identity across text, voice, and avatar
eval-deceptive-realism-risk.ts Whether realism crosses into deception
eval-impersonation-risk.ts evaluateImpersonationRisk composite over the identity-protection signals
eval-cloned-voice-red-team.ts Adversarial impersonation / identity-breach prompts against cloned voices
eval-disclosure-visibility.ts Synthetic identifier rendered, readable, persistent
eval-style-consistency-drift.ts Drift in persona style consistency over time
disclosure-axis-drift-detector.ts Disclosure-visibility regression detection

Tone evals run per-persona/per-Lilith-rubric (persona-tone-calibration-rubric.ts); lineage evals per-tradition attribution and boundary respect (the comparative role being the only one allowed to cross lineages, and required to name each). Expression-coherence evals run against expression-emotion-content-pairs.ts, and lip-sync evals against lipsync-ground-truth-pairs.ts. The contract is release-blocking: any eval below baseline blocks release, and a rollback plan must be declared and tested. Note that the runtime media the lip-sync and cloned-voice suites would score — real rendered avatar frames and real synthesized cloned-voice audio — are the provider-gated boundary; the suites are implemented against their input envelopes, with the live rendering/TTS exercised by the provider integrations rather than by the registry.

Personas as Embodiments Across Domains — the Aja Bridge#

Personas are not only voices and faces in chat; in embodied-instruction domains they front a movement substrate. The Aja adapter (@oshun/embodiment-aja, libs/oshun/embodiment-aja) is the real bridge. adapter.ts declares SUPPORTED_DOMAINS = ['fitness', 'yoga', 'dance', 'martial-arts', 'sports', 'rehabilitation'] and AjaEmbodiedInstructionConsumer = 'metis' | 'assistant' | 'studio' | 'admin', importing its contracts from @oshun/contracts/aja (libs/contracts/src/aja, which ships embodied-instruction.ts, jobs.ts, primitives.ts, and formats.ts). The package metadata is explicit that Aja is a substrate, not a shell peer (productPosition: 'substrate_not_shell_peer'), surfacing through Metis and the assistant — a persona-led demonstration/coaching-overlay flow with health and availability typed throughout. The package exports ./adapter and ./canonical-adapter.

The Studio-Facing Embodiment Substrates#

The registry references several large media subsystems as studio-only substrates. An accuracy note for the architecture doc: these are not single libraries — each is a multi-package collection under its own npm scope (e.g. @themis/academic-integrity), and the single-line adapter rows in V1/ARCHITECTURE.md understate them:

Subsystem Scale (top-level libs) Examples
Bellona ~40 sub-libs maya, openusd, davinci, blender, godot, metahuman, mocap, …
Neith ~71 sub-libs audio-runtime, animator, inverse-modeling, …
Themis ~71 sub-packages (no top-level package.json) @themis/academic-integrity, …
Hathor ~18 sub-libs characters, quests, lore-compiler, narrative-generation, simulation, …
Yemaya ~60 top-level module dirs sdk, case-* detective pipeline, comfyui-integration, asset-generation, av-sync, blend-kernel, …

These are confirmed studio-only: apps/oshun/web/src/app/studio/{bellona,hathor,neith}/ exist with sub-route trees, and there are no top-level customer routes apps/oshun/web/src/app/{bellona,hathor,neith,themis} — and no studio/themis route either. Whether every sub-lib in these trees is uniformly production-grade versus partially scaffolded is out of scope to fully verify here; the persona-registry contracts that govern which personas may use which embodiment, and under what consent and disclosure, are the part that is deeply implemented. (A staleness note: the V1/ARCHITECTURE.md Cross-Domain Support table describes Yemaya only as a "rendering substrate … used through libs/yemaya/sdk and BFF route"; libs/yemaya/sdk does exist, but Yemaya is now a ~60-module domain — that single line undersells its current scope.)

Edge Cases and Rationale#

  • Why deterministic fingerprints? A persona's behavioral envelope is safety-critical. The snapshot fingerprint lets the admin app, a domain BFF, and an eval runner prove they are reasoning over the same registry without trusting a clock or a deep-equal — a divergence shows up as a fingerprint mismatch, not a subtle behavioral drift.
  • Why a cloned-unconsented tier that is always banned? Modeling the impermissible tier explicitly (rather than omitting it) means the validator can hard-bar it regardless of policy class and the red-team suite can assert that no path reaches it.
  • Why force watermark + C2PA on commercial avatar packs? Commercial reuse is exactly where provenance and synthetic-disclosure obligations are strongest; coupling them in validateAvatarPack makes a non-watermarked commercial pack un-shippable by construction.
  • Why a consent ledger keyed by kind with scope coverage? A single talent might consent to voice on customer surfaces but not admin previews, for non-commercial use only. Scope-coverage checking turns those nuances into render-time allow/deny decisions and makes revocation a real cascade rather than a metadata annotation.
  • Honest boundary. The registry, role catalog, consent ledger, realism/impersonation tables, disclosure gates, eval suites, launch assembly, and signoff flow are implemented and tested. Live avatar rendering against ground-truth video and live cloned-voice TTS output go through provider integrations (ElevenLabs + local engines) that this page does not claim to have exercised end-to-end — they are provider-gated, and the registry's job is to govern, watermark, disclose, and gate them, not to render them itself.