# Domain Orchestration (libs/oshun)

`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](./overview.md); 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:

```mermaid
flowchart TB
  BFF["apps/*/bff · binds app.domainAdapters.&lt;domain&gt;"]
  subgraph O["libs/oshun · 49 packages (this page)"]
    DOM["domain-tara · arete · veritas · nyx · nisaba · metis"]
    SUB["memory-iris · evidence-sophia · embodiment-psyche/aja · generation-control-isis · persona-policy-lilith · persona-registry · trust-safety"]
    SHELL["shell-core · assistant · routines · desktop · wearable"]
    X["platform-foundations · analytics · privacy · payments-bridge · i18n · offline · navigation · ui · design-*"]
  end
  C["libs/contracts · @oshun/contracts (Zod shapes)"]
  S["libs/shared · @oshun/types · event-bus · persistence · ai · http-client · data-residency"]
  BFF --> O
  O --> C
  O --> S
  C --> S
```

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](./shared-libraries.md) and [Contracts](./contracts.md) 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](./bff-gateway.md).

## 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-exports `arete-relationship`, `nisaba-relationship`, `nyx-relationship`,
  and `metis-relationship`. Covered in depth on the Tara feature page; the
  contract model is `libs/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`, and
  `buildVeritasRetractionNoticeView` (`retraction-cascade.ts`) plan and surface
  the downstream invalidation when a source is retracted.
- **`domain-nyx`** (83 files) — sky events and perspective. Its `ephemeris.ts`
  is, per its own header, "REAL in-repo astronomical computation": Meeus
  algorithms for `toJulianDay`, `sunPosition`, `moonPosition`,
  `moonIllumination`, `greenwichMeanSiderealTime`, and `computeNightSky`. 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`, and `veritas-habit-grounding`
  among its modules.
- **`domain-nisaba`** (21 files) — scholarly study: the public-domain corpus,
  `concept-graph-linkages`, and `study-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 entire `src` re-exports `@metis/api-client`
  (`export * from '@metis/api-client'`, plus a `createMetisDomainAdapter`
  alias). Metis's real depth — adaptive learning, assessment, course building,
  tutor agents — lives in the dedicated `libs/metis/*` tree, the way Tara's
  audio runtime lives in `libs/tara/*` and `libs/meditation/*`. `domain-metis`
  is the namespace adapter that lets the rest of Oshun bind Metis through one
  `@oshun/domain-metis` import.

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](./persistence-data.md) and
[Auth & Identity](./auth-identity.md).

### 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`, and `shared-contracts`. It is the
  in-`libs/oshun` companion 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-domain `shared-concept-graph`.
- **`design-language`, `design-tokens`, `ui`** — the design spine.
  `design-language` (22 files) encodes the product voice as data
  (`TARA_CENTERED_PRODUCT_LANGUAGE` with its `prohibited` list of "growth
  pressure / fear-led prompts / unattributed certainty", and `OSHUN_UNIFIED_IA`
  with the customer shell `Home/Explore/Activity/Library/Assistant/Profile`).
  `design-tokens` (4 files) and `ui` (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](./persistence-data.md).
- **`payments-bridge`** (66 files) — a real settlement bridge: an
  `oracle-aggregator` that takes the **median** rate across price-feed sources
  and captures the pair-wise spread per invoice (`price-feed.ts`), a
  `receipt-signer`, a `cold-spend-queue`, an `entitlement-bus`,
  `trust-tier-disclosure`, and `security-gates`.
- **`search-discovery`** (44 files) — the honest split named above: the ranker
  is **retired from V1's live** search/recommendations paths (it scores
  `DiscoveryObject` features the candidates lack, and inventing them is
  forbidden), but its offline-eval **release gate** ships:
  `buildSearchReleaseGateSummary` (`evals/offline-evals.ts:158`) is mounted at
  `POST /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_LOCALES` is `en-US, es-US, fr-FR, de-DE, ar, he, ja-JP, pt-BR`
  (eight; `ar` and `he` carrying RTL metadata), with the documented fallback
  chain `<requested> → <language-only> → en-US` and per-locale text-expansion
  budgets.
- **`offline`** (8 files) — offline-first plumbing: an `OfflineSyncQueue`, a
  `connectivity` monitor, and `computeBackoffDelay` over a
  `DEFAULT_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](./persistence-data.md) and
[Auth & Identity](./auth-identity.md).

## How a domain call actually composes

A concrete trace, following the Tara feed from the overview down into this
layer:

```mermaid
sequenceDiagram
  participant BFF as BFF route (registerTaraRoutes)
  participant TA as app.domainAdapters.tara
  participant IRIS as memory-iris
  participant LIL as persona-policy-lilith
  participant C as @oshun/contracts/tara
  BFF->>TA: getRecommended({ userId, mood })
  TA->>C: parse request (Zod, fail loud at boundary)
  TA->>IRIS: getContinuityState({ userId, activeDomain: 'tara' })
  TA->>LIL: buildLilithSafetyAssessment(mood) for crisis handoff
  IRIS-->>TA: scoped continuity (consent-checked)
  LIL-->>TA: tone band + crisis route
  TA-->>BFF: validated slate (or typed unavailable health)
```

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](./overview.md) — the layered model this page fills in.
- [Shared Libraries](./shared-libraries.md) — the `@oshun/*` infrastructure
  these domains compose (and `buildOshunContractVersionDescriptor`'s home).
- [Contracts](./contracts.md) — the Zod vocabulary every adapter validates
  against.
- [BFF & Gateway](./bff-gateway.md) — where `app.domainAdapters` is bound and
  the domain routes are registered.
- [Persistence & Data](./persistence-data.md) — the `persistence` package, plus
  the residency/deletion machinery Iris and Privacy ride on.
- [Auth & Identity](./auth-identity.md) — the `auth` package and the identity
  that threads through every domain call.
