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_KINDS — general-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:
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 (draft→drafted,
approved→in-review, published→released) 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:
- Assets —
baseMesh,blendshapesAsset,textureSet(each anAvatarAssetRefwith a 64-hex-char SHA-256 content hash, content type, and positive byte size), ariggingVersion, the fullexposedBlendshapesset, and avisemeMapfor 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). - Watermark —
AvatarWatermarkMetadatadeclares the algorithm, whether it isappliedPerFrame, and whetherc2paEnabledprovenance is produced. - License —
AvatarLicenseMetadatawith licensor, license reference, validity window, and acommercialUseflag.
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:
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 input — requireC2paManifest 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 illustrative → stylised-3d → semirealistic-3d → photoreal-generic →
photoreal-specific (ranks 0–4). Voice naturalness runs flat-tts →
warm-synthetic → naturalistic → cloned-consented → cloned-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.tsdefinesDisclosureVisibilityFloorsand per-surface defaults (DISCLOSURE_VISIBILITY_FLOORS_PER_SURFACE). The customer surface is strictest:minTotalVisibleMs30,000 (30s cumulative),minSessionVisibleFraction0.85,minFontPixelHeight14px,minContrastRatio4.5 (WCAG AA),maxOcclusionFraction0.05.studio-previewandadminrelax these (admin: 10s, 0.6 fraction, 12px, 3.0 contrast, 0.1 occlusion).evaluateDisclosureVisibilityMeasurementturns a sampledDisclosureVisibilityMeasurementinto a pass/fail verdict.token-time-disclosure-filter.tscompiles per-persona ban tables (compilePersonaBanTable,CompiledPersonaBanTable) and feeds streaming tokens through them, emitting aTokenTimeBanIncidentEnvelopewhen phrasing crosses a banned line.disclosure-axis-drift-detector.tswatches the disclosure axis over time (evaluateDisclosureDriftagainstDISCLOSURE_DRIFT_THRESHOLDSand aDisclosureDriftBaseline) 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.
Consent — the ConsentLedger primitive#
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 canonicalLAUNCH_ROSTERofLaunchRosterEntryrows: one persona per family, each withfamilyId, derivedaudience(customer/operator),launchSurfaces, a releasewave(wave-1/wave-2/wave-3, where wave-1 is the minimum viable launch), and apremiumCastflag set when the persona uses a real person's likeness, lineage, or name. Lookups:listLaunchRoster,findLaunchEntryByPersonaId,listLaunchEntriesByFamily/ByWave/ByAudience, all validated byvalidateLaunchRoster.launch-multimodal-assignments.ts—LAUNCH_MULTIMODAL_ASSIGNMENTSmaps each launch persona to its concrete voice profile and avatar pack;listLaunchVoiceProfiles/listLaunchAvatarPacksmaterialize the assigned media, andvalidateAllLaunchMultimodalAssignmentschecks coherence across the cast.launch-persona-config.ts—LaunchPersonaProductionConfigties together the prompt config (PERSONA_STYLE_DIRECTIVES), policy overrides, grounding config (PERSONA_CITATION_POSTURES), memory config (PERSONA_MEMORY_SCOPES,PERSONA_MEMORY_MODESofdurable/ephemeral/suppressed,PERSONA_SENSITIVE_CATEGORIES), disclosure config, and entitlement config — the per-persona production wiring.launch-family-signoff.ts— the multi-party signoff engine:evaluateLaunchPersonaSignoffper persona,evaluateLaunchFamilySignoffper family, andevaluateAllLaunchFamiliesSignofffor the whole cast, each requiring captured signoff and aLaunchRollbackPlanEvidencerollback plan, withsummarizeLaunchSignoffrolling the verdict up. Thelaunch-family-signoff.e2e.test.tsandadmin-approval-rollback.e2e.test.tsexercise 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-unconsentedtier 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
validateAvatarPackmakes 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.
Related#
- Lilith Persona Policy — the seven roles, tone bands, capability ceilings, and the policy pack a persona binds to
- Iris Memory and Identity — per-persona memory scope and boundary enforcement
- Isis Generation Control — the release gate for voiced/avatar personas
- Generation Audience Tiers and Surface Boundaries — surface and entitlement gating
- External Model Intelligence and Execution Providers — the swappable voice/TTS providers
- Sophia Grounding — grounding-fidelity scorecards for pedagogical personas
- Creator Surfaces, Voice, Music, and 3D Generation — the studio embodiment substrates (Bellona, Neith, Yemaya, …)
- Mentor Presence — Meditating with a Master — the embodied-mentor experience that consumes these avatar/voice/consent contracts in the meditation player (§36; implemented, release-gated)
- Privacy, Consent, Data Portability, and User Controls — consent at the platform level
- Subsystem Glossary — definitions for Aja, Lilith, Isis, and the studio substrates
- The features hub: ../features.md