libs/oshun/ is the layer where a substrate primitive becomes a product
capability. It is the 49-package tree that sits directly above the
domain-agnostic infrastructure (libs/shared/, the @oshun/* packages) and the
validated boundary (libs/contracts/), and directly below the
backend-for-frontend tier (apps/*/bff). Iris is a memory store; memory-iris
turns it into a consent-scoped, tiered, conflict-resolving memory service that
the assistant and all six domains share. Sophia is a grounding engine;
evidence-sophia turns it into a versioned, role-scoped evidence contract
that Veritas, Nisaba, and Metis bind to. The same move repeats 49 times:
substrate in, product service out. As of this writing the tree holds
approximately 1,885 TypeScript files (about 1,198 excluding tests) across
those 49 packages, every one carrying a package.json name under the @oshun/*
namespace.
These libraries are shared rather than per-product for the same structural
reason the platform itself exists (the §5 one-canonical-home rule): nine
products and several dozen domains all need the same memory model, the same
grounding contract, the same persona-safety gate, and the same disclosure
registry, and each of those is written once here and composed everywhere. A
domain library is allowed to depend on the two trees below it — it imports
@oshun/contracts for its shapes and @oshun/event-bus, @oshun/types,
@oshun/persistence, and the rest of libs/shared for its plumbing — and is
never depended on by them. This page is one slab of the stack described in
the platform overview; read that first for the layered model
this fills in.
What ships, honestly#
The dependency direction is real and verifiable, not aspirational. A grep for
any libs/shared/ or libs/contracts/ source importing a libs/oshun/ domain
package (@oshun/domain-*, @oshun/memory-iris,
@oshun/persona-policy-lilith, the shells, …) returns nothing — the
substrate genuinely does not reach up into the domains. The versioning machinery
the domain adapters use, buildOshunContractVersionDescriptor, lives below
them in libs/shared/types/src/contracts.ts:105; the domains compose it, they
do not own it.
Maturity is uneven, and this page labels it rather than implying uniform depth.
The deep, load-bearing packages are unambiguous: persona-registry (137 files),
analytics (151), domain-veritas (103), domain-nyx (83),
persona-policy-lilith (76), memory-iris (71), payments-bridge (66),
domain-tara (54), embodiment-psyche (51), shell-core (49), and
generation-control-isis (41) are real services with domain-specific algorithms
and substantial test suites. At the other end, several packages are honestly
thin by design: domain-metis (3 files) is a re-export façade over the
@metis/api-client package whose depth lives in the dedicated polyglot
libs/metis/* tree; embodiment-aja (5 files) is an
adapter-contract-plus-canonical-adapter bridge, not a runtime; design-tokens
(4 files) and ui (8 files) are small foundational surfaces. One package is
explicitly retired from V1 scope: @oshun/search-discovery's ranker is
not adopted by the live /v1/search and /v1/recommendations paths (audit
E5, 2026-06-11, documented at the top of
libs/oshun/search-discovery/src/index.ts), because it scores DiscoveryObject
features the live candidates do not carry — though its offline-eval release
gate does ship live (see below). Where a thing is gated on an injected
external dependency, the library fails loud rather than fabricating success;
that posture is the spine of the section that follows.
The dependency contract#
The split that makes this tree reusable is the same one the overview names, seen from inside the domain layer:
Every arrow points down. libs/contracts/ gives the domains their vocabulary
(@oshun/contracts/metis, @oshun/contracts/tara, …) with no behaviour;
libs/shared/ gives them their plumbing —
buildOshunContractVersionDescriptor from @oshun/types, the event bus, the
persistence drivers, the @oshun/data-residency routing helpers — with no
domain knowledge. Because nothing below imports anything here, a change to
domain-veritas cannot ripple down into the event bus, and a contract edit is a
single type-checked change every domain sees at once. See
Shared Libraries and Contracts for
the two trees below.
The canonical adapter pattern#
Almost every substrate and domain library in this tree exposes the same shape: a
versioned adapter contract. This is the single most important architectural
fact about libs/oshun/, because it is how a surface consumes a domain without
coupling to its internals. Each contract is an oshun.<area>.<name>.adapter
descriptor built through the shared buildOshunContractVersionDescriptor,
pinned to a semantic version with a minimumCompatibleVersion and a
compatibilityMode:
| Library | Contract id | Version |
|---|---|---|
memory-iris |
oshun.memory.iris.adapter |
1.0.0 (adapter.ts:63) |
evidence-sophia |
oshun.evidence.sophia.adapter |
1.0.0 |
generation-control-isis |
oshun.generation.isis.adapter |
1.0.0 (adapter.ts:78) |
embodiment-psyche |
oshun.embodiment.psyche.adapter |
1.0.0 (adapter.ts:76) |
embodiment-aja |
oshun.embodiment.aja.adapter |
1.0.0 (adapter.ts:82) |
persona-policy-lilith |
oshun.persona_policy.lilith.adapter |
1.0.0 (adapter.ts:67) |
domain-tara |
oshun.domain.tara.adapter |
(domain-adapter.ts:152) |
domain-arete |
oshun.domain.arete.adapter |
(domain-adapter.ts:181) |
domain-veritas |
oshun.domain.veritas.adapter |
(domain-adapter.ts:159) |
domain-nyx |
oshun.domain.nyx.adapter |
(domain-adapter.ts:222) |
domain-nisaba |
oshun.domain.nisaba.adapter |
(domain-adapter.ts:211) |
Each contract carries four things beyond its id: a metadata descriptor (the
substrate's posture — Iris declares role: 'memory_substrate',
productPosition: 'substrate_not_shell_peer',
directSurface: 'assistant_and_settings'); a declared consumer set (Iris
lists
assistant, tara, arete, veritas, nyx, nisaba, metis, admin, studio, support —
adapter.ts:275); a capability vocabulary (Iris:
assistant_identity, durable_memory, continuity_state, memory_scopes, memory_scope_hierarchy, consent_aware_controls, privacy_review, searchable_recall, memory_export, memory_deletion
— adapter.ts:287); and an availability probe that reports per-subsystem
ok | degraded | unavailable rather than throwing. Capabilities are
role-scoped: Isis defines ISIS_GENERATION_CONTROL_ADAPTER_ROLE_CAPABILITIES so
a non-admin role sees a narrowed surface, exactly as Sophia's
grounding | review | admin read roles do (detailed in the Sophia feature
page).
The pattern's payoff is at the BFF boundary. apps/oshun/bff/src/app.ts:565
decorates the app with domainAdapters (typed OshunDomainServiceAdapters),
defaulting to createDefaultDomainAdapters() but injectable — tests pass
createMockDomainServiceAdapters(). Routes then call
app.domainAdapters.arete.getStreakStats(...) or
app.domainAdapters.nyx.getEventReminders(...) (server.ts:707, :714)
without importing a domain's internals. The registry in
apps/oshun/bff/src/adapters/domain-service-adapters.ts imports only the
canonical types from each domain (@oshun/domain-arete,
@oshun/domain-veritas, @oshun/domain-nisaba, @oshun/domain-metis/adapter)
and wraps them in a DomainServiceCircuitBreaker with
buildUnavailableDomainHealth and PartialFailureError handling — so an
unavailable domain degrades to a typed fail-loud health record instead of a 500.
The BFF actually consumes 29 of these packages today; the binding is real, not
decorative. See BFF & Gateway.
The six customer domains#
These are the product-facing domains a V1 customer experiences as tabs. Each
ships a contract-validated object model, an adapter, a card-model and
launch-actions/deep-links surface, and a set of cross-domain relationship
modules that let a domain compose its siblings rather than duplicate them.
domain-tara(54 files) — contemplative practice: rituals, breathwork cadences, a session state machine, and lineage syncretism gates. Its barrel re-exportsarete-relationship,nisaba-relationship,nyx-relationship, andmetis-relationship. Covered in depth on the Tara feature page; the contract model islibs/contracts/src/tara.domain-veritas(103 files, the largest) — grounded stories and claims. It is built as composite namespaces (AttestorWorkflow,CounterclaimBalance,RetractionCascadeUx,ContradictionDetection,EditorialStateMachine) and ships the real retraction machinery:planVeritasSourceRetractionCascade,summarizeVeritasRetractionCascade, andbuildVeritasRetractionNoticeView(retraction-cascade.ts) plan and surface the downstream invalidation when a source is retracted.domain-nyx(83 files) — sky events and perspective. Itsephemeris.tsis, per its own header, "REAL in-repo astronomical computation": Meeus algorithms fortoJulianDay,sunPosition,moonPosition,moonIllumination,greenwichMeanSiderealTime, andcomputeNightSky. The comment is explicit that the system must not fabricate sky data on backend failure — the ephemeris is computed, not mocked.domain-arete(45 files) — goals, habits, reflection:streak-recovery,friction-taxonomy,coaching-summary-surface, andveritas-habit-groundingamong its modules.domain-nisaba(21 files) — scholarly study: the public-domain corpus,concept-graph-linkages, andstudy-plans. This is the corpus Sophia's live answer path actually retrieves over.domain-metis(3 files) — education and tutoring, and the honest thin one: its entiresrcre-exports@metis/api-client(export * from '@metis/api-client', plus acreateMetisDomainAdapteralias). Metis's real depth — adaptive learning, assessment, course building, tutor agents — lives in the dedicatedlibs/metis/*tree, the way Tara's audio runtime lives inlibs/tara/*andlibs/meditation/*.domain-metisis the namespace adapter that lets the rest of Oshun bind Metis through one@oshun/domain-metisimport.
The relationship modules are why a Tara sit can offer a Nisaba passage or an Arete next step without Tara owning Nisaba's or Arete's model: the dependency is a typed re-export, composed at the call site.
The substrate-orchestration libraries#
These have no consumer tab of their own; they are the services every domain leans on, each fronted by the canonical adapter above.
memory-iris (71 files)#
The shared memory service. Its model is genuinely tiered and scoped, not a
key-value store: scopes run
assistant_profile, session, conversation, domain, cross_domain, notebook, tenant
and canonical tiers run core, working, archival, episodic, semantic
(types.ts). Retention is concrete and per-scope — scope-hierarchy.ts ships
IRIS_SESSION_RAW_RETENTION_DAYS = 30,
IRIS_SESSION_SUMMARY_RETENTION_DAYS = 90, IRIS_POSE_RAW_RETENTION_DAYS = 7,
IRIS_TENANT_MEMORY_RETENTION_DAYS = 365, and an
IRIS_SESSION_PROFILE_PROMOTION_THRESHOLD = 3 that governs when a repeated
session fact is promoted into the durable profile
(evaluateIrisSessionProfilePromotion). Concurrent writes are reconciled by a
real conflict resolver: resolveIrisMemoryWriteConflict derives a conflict key
from the write or record (deriveConflictKeyFromWrite /
deriveConflictKeyFromRecord), classifies the source kind, and appends an audit
event (appendIrisMemoryConflictAuditEvent) — memory writes are conflict-aware
and audited, not last-write-wins. Consent runs through the model end to end
(consent-ledger, data-rights, privacy-suppression, admin-inspection).
Iris threads into the persistence and privacy stories on
Persistence & Data and
Auth & Identity.
evidence-sophia (14 files)#
The canonical evidence contract — SOPHIA_EVIDENCE_ADAPTER_CONTRACT
(oshun.evidence.sophia.adapter, 1.0.0), the source-set lifecycle
(computeSophiaSourceSetHash, evaluateSophiaSourceSetReadiness), and the
planSophiaSourceLifecycleInvalidation primitive. The adapter is deliberately
an interface over an injected @sophia/client-shaped dependency: when that
binding is absent the BFF routes fail closed with
502 evidence_adapter_unavailable rather than inventing a result. The deeper
engines it fronts (BM25, the fact-check and contradiction loops in
libs/sophia/*) are real but unwired on the live answer path. This package is
the contract; the running behaviour is documented on the Sophia grounding
feature page.
embodiment-psyche (51 files) and embodiment-aja (5 files)#
The embodiment substrates, and a clean example of honest maturity variance.
embodiment-psyche is the deep real-time avatar runtime: a session-envelope
with transport tiers and capabilities, provider-failover for mid-turn provider
loss (planPsycheProviderFailoverMidTurn), backpressure,
reconnect-behavior, and a real quality gate.
PSYCHE_QUALITY_THRESHOLD_DEFAULT_POLICY (quality-thresholds.ts:52) pins
floors of lip-sync-alignment 0.86, expression-coherence 0.82, and
voice-naturalness 0.80 (per-locale, en-US 0.86), with
maxRerenderAttempts: 2 and a degradation ladder of
pass → re-render → fallback-to-voice → fallback-to-text — when an avatar frame
fails its floor twice it degrades to voice, then text, rather than shipping a
bad render. embodiment-aja, by contrast, is a thin
embodied_instruction_bridge: its five files are the adapter contract and
canonical adapter only, with the same substrate_not_shell_peer posture but no
runtime of its own.
generation-control-isis (41 files)#
The generation control plane: buildIsisGenerationControlPlan,
buildIsisGenerationExecutionSummary, model/provider/workflow registries, a
dispatch-guard (evaluateIsisDispatch admits or refuses a runtime request),
and a cryptographic provenance bundle. provenance-bundle-schema.ts pins
CANONICAL_PROVENANCE_BUNDLE_SPEC_VERSION = 1, Crockford-base32 claim ids
(claim_[0-9a-z]{26}), hash algorithms sha256 | sha512 | blake3, and
signature algorithms ed25519 | ecdsa-p256 — generated artifacts carry signed,
versioned provenance. Isis also governs ComfyUI workflows and a CivitAI
intake/review pipeline (comfyui-governance.ts, civitai-review-pipeline.ts).
persona-policy-lilith (76 files), persona-registry (137 files), trust-safety (20 files)#
The safety and persona triad. persona-policy-lilith is the tone-and-crisis
gate: buildLilithToneGuidance, buildLilithVoiceSafetyPolicy,
buildLilithSafetyAssessment, and a pluggable crisis analyzer
(analyzeLilithSafetyViaCrisisPolicy, createLilithCrisisSafetyAnalyzer,
mergeLilithSafetyAnalyses), backed by a wall of real evaluation suites —
eval-crisis-handling, eval-tone-quality, eval-unsafe-claim,
eval-spiritual-boundary, eval-clone-abuse-resistance,
eval-regression-blockers. This is the substrate behind Tara's crisis handoff
and contemplative tone review. persona-registry is the canonical,
disclosure-first registry of every persona the shell, domains, and admin
surfaces look up by id — pure data and pure functions
(get/list/filter/validate/fingerprint), with avatar release gates, cloned-voice
red-team evals, and impersonation-risk and disclosure-visibility measurement.
trust-safety is the cross-cutting policy spine: policy-taxonomy, severity,
decisions, crisis, abuse-patterns, operator-surfaces, and evaluation.
Together they make safety structural rather than a per-product afterthought.
The shells#
The shell libraries are the cross-domain surfaces a customer moves between
domains through. shell-core (49 files) is the consumer shell's entry-point and
domain-navigation model — ConsumerShellEntryPointDescriptor,
buildConsumerShellEntryPointHref, the canonical domain-navigation context.
shell-assistant (48 files) is the voice-first cross-domain assistant:
createAssistantEngine orchestrates intent classification, domain action
routing, and response formatting across Tara, Veritas, Nyx, Arete, Nisaba, and
Metis via an injected AssistantDomainAdapters — the same adapter-injection
seam the BFF uses. shell-routines (11 files) composes morning/evening routines
that span Tara and Arete steps (TaraBreathworkStepConfig,
AreteEveningReflectionConfig). shell-desktop (19 files) is a
framework-agnostic desktop surface (windows, tray, global shortcuts, the
oshun:// deep-link protocol, auto-update). shell-wearable (17 files) is the
watch/wearable companion: complications, streak widgets, smart-timed reminders,
haptic patterns. The shells hold orchestration, not domain logic — they call
domain adapters, exactly like the BFF does.
Foundations, design, and cross-cutting services#
The remaining libraries are the platform-shaped concerns the domains share.
platform-foundations(20 files) — the genuinely domain-agnostic core that even the substrates lean on, and notably it declares zero npm dependencies. It barrels nine submodules:service-discovery,public-api(OAuth),role-model,step-up(step-up auth),secrets,configs,rollback,abuse-controls, andshared-contracts. It is the in-libs/oshuncompanion to the@oshun/*infrastructure proper.navigation(26 files) — the canonical route, IA, and journey model:customer-ia,admin-ia,tenant-ia,platform-shells,daypart-journeys, and the cross-domainshared-concept-graph.design-language,design-tokens,ui— the design spine.design-language(22 files) encodes the product voice as data (TARA_CENTERED_PRODUCT_LANGUAGEwith itsprohibitedlist of "growth pressure / fear-led prompts / unattributed certainty", andOSHUN_UNIFIED_IAwith the customer shellHome/Explore/Activity/Library/Assistant/Profile).design-tokens(4 files) andui(8 files) are the small, foundational token/component/motion/theme surfaces — thin on purpose.analytics(151 files) — a large, real taxonomy and pipeline: typed customer/admin/assistant/flows/release event taxonomies (the customer taxonomy alone declares 77 distinct event names), buffered sinks, a validation layer, KPI dashboards, and a tracing manifest.privacy(18 files) —consent,residency,export-deletion,dsar,compliance, and the privacy surface; the user-facing half of the same residency and deletion machinery on Persistence & Data.payments-bridge(66 files) — a real settlement bridge: anoracle-aggregatorthat takes the median rate across price-feed sources and captures the pair-wise spread per invoice (price-feed.ts), areceipt-signer, acold-spend-queue, anentitlement-bus,trust-tier-disclosure, andsecurity-gates.search-discovery(44 files) — the honest split named above: the ranker is retired from V1's live search/recommendations paths (it scoresDiscoveryObjectfeatures the candidates lack, and inventing them is forbidden), but its offline-eval release gate ships:buildSearchReleaseGateSummary(evals/offline-evals.ts:158) is mounted atPOST /v1/search/offline-eval(apps/oshun/bff/src/search/offline-eval-route.ts) and computes real NDCG@10 / MAP@10 / recall@100 / coverage / diversity per slice with a pass/fail gate.i18n(2 files, one a 721-line catalog) — the canonical locale catalog:OSHUN_LAUNCH_LOCALESisen-US, es-US, fr-FR, de-DE, ar, he, ja-JP, pt-BR(eight;arandhecarrying RTL metadata), with the documented fallback chain<requested> → <language-only> → en-USand per-locale text-expansion budgets.offline(8 files) — offline-first plumbing: anOfflineSyncQueue, aconnectivitymonitor, andcomputeBackoffDelayover aDEFAULT_RETRY_POLICY.
Two further libs/oshun packages — persistence (137 files) and auth/
auth-client (56 files) — live in this tree but are deep enough to own their
own pages: see Persistence & Data and
Auth & Identity.
How a domain call actually composes#
A concrete trace, following the Tara feed from the overview down into this layer:
Each hop borrows a shared foundation: the request shape is a Zod contract from
libs/contracts, the continuity read is the memory-iris adapter under its
consent rules, the crisis gate is the persona-policy-lilith substrate, and an
unavailable domain returns a typed buildUnavailableDomainHealth record through
the BFF's circuit breaker rather than a fabricated slate. No step re-implements
memory, validation, or safety — each is one of these 49 services, composed.
Related#
- The Shared Platform — the layered model this page fills in.
- Shared Libraries — the
@oshun/*infrastructure these domains compose (andbuildOshunContractVersionDescriptor's home). - Contracts — the Zod vocabulary every adapter validates against.
- BFF & Gateway — where
app.domainAdaptersis bound and the domain routes are registered. - Persistence & Data — the
persistencepackage, plus the residency/deletion machinery Iris and Privacy ride on. - Auth & Identity — the
authpackage and the identity that threads through every domain call.