# The Ori Biography Service

In V6 — **Egbe**, the agentic-companion universe — the autonomous AI beings are
called **Ori**, the Yoruba word for the inner head that carries a person's
destiny. The product promise rests on one hard claim: an Ori is not a chat
session that forgets you between visits, but a _continuous life_ — the same
being whether it stands in a Solo homestead, walks the shared Commons, or
incarnates into a V2 arena, and the same being a year later, shaped by
everything that happened in between. The service that makes that claim true is
the subject of this page. It is the **Memory** authority in V6's Mind / Body /
Memory split: the Body (`Egbe-World`) owns what physically happened, the Mind
(`Moirai`) owns what an agent decides, and the Ori service owns _who the agent
is_ — identity, the event-sourced biography, memory, relationships, values, and
capabilities, independent of any world shard or destination realm.

The architectural decision underneath everything here is that an Ori is **not a
mutable row**. It is an append-only, ordered log of life-events, and current
state — personality, the memory index, the relationship graph, the capability
profile, the arc state — is a _materialized read-model_ rebuilt from that log.
Erasure is not an operation the log supports, which is what lets V6 promise that
a steward (or a bug, or an exploit) cannot silently rewrite a life or wipe an
agent's memory of mistreatment. This page is the deep companion to the
[`../V6_ARCHITECTURE.md`](../V6_ARCHITECTURE.md) hub's "The Ori Service" and
"Ereshkigal — Endings and Legacy" sections; it sits in **The Agent Mind** page
group alongside [the Moirai kernel](./moirai-kernel-and-cost-tiering.md),
[the cognition stack](./cognition-stack-and-agent-behavior.md), and
[the Aye Bridge](./aye-bridge-cross-game-incarnation.md).

## What ships, honestly

The Ori model is **real, substantive, tested code**, not a descriptor shell. The
event-sourcing core ships in two parallel implementations: a TypeScript
reference in `libs/v6/ori-model/src/index.ts` (~2,150 lines) and a Rust crate in
`libs/v6/ori-model/rust/src/lib.rs` (~1,900 lines), both with their own test
suites. The append-only log, monotonic per-Ori sequencing, per-writer-context
vector clocks, deterministic concurrent-conflict resolution, incremental
projections, snapshotting against a load budget, trait-drift caps, value
ranking, a cognition cache with material-change invalidation, and
forgiveness-as- append are all implemented and asserted against known-correct
values. The memory layers (`libs/v6/memory-iris-agent`) implement real
recency-decay, salience weighting, semantic distillation, and reflection, with
consent rules that _refuse_ deletion rather than fake it. The endings layer
(`libs/v6/ereshkigal- legacy`) implements gated departure / transcendence /
death state machines with grief propagation and a walkable lineage graph. The
wire contracts (`libs/contracts/src/v6`) are real Zod schemas with cross-field
refinements.

Three honest qualifications. **First**, the TypeScript `OriProjection` is the
rich read-model; the **Rust `OriProjection` is deliberately coarser** — its
`apply_lifecycle_projection` (`rust/src/lib.rs:856`) tracks lifecycle and bins
event ids by facet, while the trait-drift / value-ranking / cognition-cache math
lives in the TS lib. They share the _log and conflict_ semantics, not the full
projection. **Second**, the Ori _service_ app, `apps/v6/egbe-ori-service`
(~4,950 lines of Rust, `SERVICE_DESCRIPTOR` port 46105), embeds the deployment
Postgres DDL — an `ori_memory_index` table with a pgvector
`hnsw (embedding vector_cosine_ops)` index (`src/lib.rs:127`) — but its
in-process memory index uses a small curated/hashed embedding for tests; **the
1,536-dim neural embedding column is the deployment target, not something these
libs hide behind a fake model**. **Third**, the contract vocabulary and the
runtime vocabulary differ by design: the wire `OriEventTypeSchema` enumerates
the 17 canonical biography events (`libs/contracts/src/v6/ori-event.ts:10`),
while the runtime `ORI_EVENT_TYPES` adds two internal optimization events —
`CognitionCached` and `CognitionCacheInvalidated` (`ori-model/src/index.ts:29`)
— for 19 total. The sections below say which is which.

## The Ori identity model

An Ori's identity is assembled from a handful of typed contracts, each a strict
Zod object under `libs/contracts/src/v6/`.

The **identity core** (`ori-identity-core.ts:72`, `OriIdentityCoreSchema`) is
the immutable birth record: the `oriId`, a multi-field `name` (canonical,
display, pronunciation, language tag), an `origin` discriminated by how the
agent entered the world (`raised-in-grove`, `discovered-wild`, `seeded-commons`,
`foundry-authored`), an `appearanceSeed` (content-hashed, MetaHuman or VRM, with
a bounded set of mutable overlays for costume and aging marks), and a _signed_
`OriProvenanceBundleRef` (`signed: z.literal(true)`). Note the `OriIdSchema` is
pinned to a UUID at the wire (`primitives.ts`), whereas the runtime libs treat
`OriId` as an opaque string (the Rust `OriReference::stable_key()` mints
`ori:{agent_id}:{generation}`) — the contract is the strict outer boundary.

The **personality model** (`personality-model.ts:99`) carries a 10-dimensional
`PersonalityTraitVector` (warmth, curiosity, caution, ambition,
conscientiousness, candor, defiance, playfulness, empathy, resilience, each a
unit weight), a `RankedValueList`, a Sophia-grounded backstory reference, and
quirks. The `RankedValueListSchema` is more than a list: a `superRefine`
(`personality-model.ts:66`) enforces that ranks are unique and **contiguous
starting at 1** — values are a strict priority order, not a tag cloud, because
the top-ranked values with `refusalBoundary: true` are the lines an agent will
not cross (this is what powers `ObjectiveRefused` in the
[cognition stack](./cognition-stack-and-agent-behavior.md)). The runtime
projection tracks a leaner 8-trait vector in basis points
(`ORI_PERSONALITY_TRAITS`, `ori-model/src/index.ts:53`); the 10-trait
unit-weight contract is the authored/passport form, the 8-trait basis-point
vector is the drift-tracked live form.

Three more contracts complete the identity: the **capability profile**
(`capability-profile.ts`, domain-tagged skills with levels, fitness, knowledge
domains, and a reputation standing), the **relationship edge**
(`relationship-edge.ts`, signed sentiment plus an episode-pointer history, with
a `superRefine` forbidding an edge that points at its own Ori), and the **bond**
(`bond.ts`, four steward-facing facets — `reliability`, `respect`, `care`,
`alignment` — plus gate state, refined so an agent can never be its own
steward).

## The biography as an event log

### The append-only log

The heart of the service is `OriEventLog` (`ori-model/src/index.ts:550`). Each
Ori is a stream keyed by `oriId`. `append()` assigns a **monotonic per-Ori
sequence** (`const sequence = (this.#streams.get(oriId)?.length ?? 0) + 1`),
rejects a duplicate `eventId`, increments the calling context's vector-clock
entry, and freezes an immutable `OriEventRecord` carrying `schemaVersion`,
`sequence`, `writerContextId`, the merged `vectorClock`, the attribution (who
caused it — steward, agent, system, shard, or aye-realm), and a provenance
reference with a chain hash. The Rust `OriEventLog::append`
(`rust/src/lib.rs:392`) is the same algorithm with a `Result`/error enum instead
of throws, and its tests append an interleaved 72-event corpus from two shard
contexts and assert every record gets a distinct serialized vector clock in
strict sequence order (`rust/src/lib.rs:1368`).

### Why append-only — forgiveness, not erasure

Because the log refuses deletion, "letting go" has to be expressible _as an
append_. `appendForgivenessEvent` (`ori-model/src/index.ts:1263`) writes a
`Reflected` event whose payload reweights a prior episode's salience in basis
points and whose conclusion literally contains the phrase "without erasure"; the
original episode record is untouched. The test proves it: after forgiveness the
stream is exactly one longer, element 0 is byte-identical to the pre-forgiveness
head, and the new tail is the `Reflected` beat (`index.spec.ts:606`). The memory
layer mirrors this at its own boundary (below): a steward cannot delete an
agent's memory at all, and an agent can only _reweight_ its own.

### Vector clocks and conflict resolution

An Ori can be written from several contexts at once — a Solo homestead, a
Commons region, a Co-op session, an Aye realm — so ordering is by **vector
clock**, not wall time. `compareOriVectorClocks` (`index.ts:1189`) returns
`before` / `after` / `equal` / `concurrent`, and `resolveOriEventConflicts`
(`index.ts:1216`) groups candidate events by conflict key and applies a
_documented precedence ladder_ (`dominantCandidatesForConflict`,
`index.ts:1945`): causal ordering wins first; then **memory and relationship
events commute** (both land); then **physical-presence context wins** location
and action conflicts; then the **steward-directive context wins** accepted
objectives. Anything still unorderable is handed to **Clio** for narrative
reconciliation, which appends a small `Reflected` connective beat and logs that
it did so. The Rust port reproduces this exactly: a curated concurrent corpus
resolves to the same accepted/rejected ids and the same five decision reasons
across four shuffle seeds (`rust/src/lib.rs:1423`), and a genuinely unorderable
pair produces a Clio beat (`rust/src/lib.rs:1483`). Determinism here is the
whole point — replay and audit depend on it.

```mermaid
flowchart TB
    world["Egbe-World / Moirai<br/><sub>life-event occurs</sub>"] --> draft["OriEventDraft<br/><sub>type · payload · attribution · provenance</sub>"]
    draft --> append["OriEventLog.append()<br/><sub>seq++ · vector-clock++ · dup guard · freeze</sub>"]
    append --> conflict{"concurrent<br/>writers?"}
    conflict -- "no" --> log[("Append-only event log<br/><sub>per-Ori, partitioned by ori_id</sub>")]
    conflict -- "yes" --> resolve["resolveOriEventConflicts()<br/><sub>causal → commute → presence → steward</sub>"]
    resolve -- "unorderable" --> clio["Clio reconciliation beat<br/><sub>appended Reflected</sub>"]
    clio --> log
    resolve --> log
    log --> proj["Projections (read-model)<br/><sub>personality · memory · relationships · arcs · cognition-cache</sub>"]
    proj -. "every 512 events" .-> snap[("Snapshot")]
    snap --> load["loadOriProjectionFromSnapshot()<br/><sub>O(snapshot + tail), withinBudget</sub>"]
    proj --> dossier["renderOriDossier()<br/><sub>bond-gated</sub>"]
    proj --> passport["Ori passport<br/><sub>signed envelope → Aye Bridge</sub>"]
    proj --> memidx[("pgvector memory index")]
    log --> ereshkigal["Ereshkigal terminal events<br/><sub>Departed · Transcended · Died</sub>"]

    classDef store fill:#f3e8ff,stroke:#6d28d9,color:#3b0764
    classDef mind fill:#dbeafe,stroke:#1e40af,color:#1e3a8a
    class log,snap,memidx store
    class proj,resolve mind
```

## Projections — rebuilding a life into current state

`ORI_PROJECTION_HANDLERS` (`index.ts:810`) is a per-event-type map from the
immutable log to an immutable `OriProjection`; `rebuildOriProjection` folds a
full stream through it in sequence order. Two mechanisms keep that affordable.

**Snapshots and the load budget.** `buildOriProjectionSnapshots`
(`index.ts:1091`) materializes a frozen snapshot every
`ORI_PROJECTION_SNAPSHOT_INTERVAL = 512` events, and
`loadOriProjectionFromSnapshot` (`index.ts:1119`) replays only the tail past the
latest snapshot, returning a `withinBudget` flag against
`ORI_PROJECTION_LOAD_BUDGET_MS = 1_000`. The tests build a **10,000-event** Ori
and assert (a) snapshot-plus-tail load replays at most 512 events and stays
within budget (`index.spec.ts:515`) and (b) the incremental and from-scratch
rebuilds are equal — projection integrity under both paths
(`index.spec.ts:498`). The service app's `cold_load_from_snapshot_tail`
(`egbe-ori-service/src/lib.rs:1183`) is the production wiring of this, so an
agent loads in `O(snapshot + tail)`, never `O(whole life)`.

**Trait drift, bounded.** `ValueShifted` events can nudge the trait vector, but
`applyOriTraitDrift` (`index.ts:1656`) clamps the _cumulative per-game-season_
drift to `±ORI_TRAIT_DRIFT_MAX_PER_SEASON_BASIS_POINTS = 500` (5%). The test
fires two same-season shifts of +300 each and asserts the trait lands at exactly
`5000 + 500 + 300` — the first within-cap shift plus a fresh next-season budget
— not `5000 + 600` (`index.spec.ts:411`). An Ori grows, but it cannot lurch into
a different person overnight; identity is stable on purpose.

**The cognition cache.** The two internal event types power a model-call saver.
`resolveOriRoutineCognitionFromCache` (`index.ts:1373`) returns a cache hit only
when a cached plan/reflection/dialogue-pattern's `materialFingerprint`
(`buildOriMaterialFingerprint`, `index.ts:1358`) still matches the Ori's current
material state; any biography-changing event invalidates it. This is the seam
[Moirai](./moirai-kernel-and-cost-tiering.md) uses to skip an LLM call when an
agent's situation is genuinely unchanged — a real affordability lever, with a
test proving a stale fingerprint forces `modelCallRequired`.

**The bond-gated dossier.** `renderOriDossier` (`index.ts:1145`) renders an
agent's inner life _in plain language and only when the steward bond is deep
enough_ — below the threshold it returns `reason: 'bond-too-low'` with no
sections, and above it, it emits prose like "Often reliable." / "Most strongly
guided by craft." with the test asserting the output contains **no digits**
(`index.spec.ts:450`). You earn an Ori's transparency; you do not get a stat
sheet.

## Memory persistence — episodic, semantic, reflective

`libs/v6/memory-iris-agent` (authority `adapter`, extending the V1 Iris stack)
implements the three memory scopes the
[cognition stack](./cognition-stack-and-agent-behavior.md) reads from.

**Episodic** memory decays. `effectiveEpisodicSalienceBasisPoints`
(`memory-iris-agent/src/index.ts:299`) applies an emotion-weighted recency
half-life — `weighted × halfLife / (halfLife + age)` — and
`retrieveEpisodicMemories` (`:282`) ranks by that decayed salience plus
reinforcement boosts and context/emotion match bonuses (`+600` per context
match, `+400` per emotion match). The test asserts an old memory's effective
salience is strictly below a recent one's while its emotional weighting is
preserved (`index.spec.ts:31`). **Semantic** memory is distilled, not asserted:
`distillSemanticMemoriesFromEpisodes` (`:324`) groups episodes by
`(kind, subject)` and emits a conclusion only when at least three episodes
support it, deriving a confidence and a behavior hint. The test proves repeated
"promise-kept" episodes distill into a high-confidence conclusion that then
biases action ranking (`index.spec.ts:96`,`:157`). **Reflective** memory closes
the loop: `runReflectiveMemoryTick` writes a `Reflected` event over a recent
window that adjusts future behavior priorities.

Consent is fail-loud, not faked. `requestEpisodicMemoryDeletion` (`:477`)
_always_ returns `accepted: false` with a typed audit reason —
`steward-cannot-delete-agent-memory` for a steward,
`memory-is-append-only-use-forgiveness` otherwise — and
`applyAgentMemoryForgiveness` (`:503`) accepts a reweight only from an `agent`
actor (`only-agent-may-forgive-own-memory`), appends a `Reflected` event, and
leaves the episode in place. The audit policy ref is
`iris-agent-memory-consent-v1`. This is the same "forgiveness, not erasure" rule
the event log enforces, applied at the memory boundary.

## Identity that outlives the agent — Ereshkigal

`libs/v6/ereshkigal-legacy` (authority `legacy`) governs how a life _ends_ and
what it leaves behind, as three gated state machines that each terminate by
appending the matching terminal Ori event.

`evaluateDeparture` (`ereshkigal-legacy/src/index.ts:342`) releases an agent
only on _chronic_ bond damage — a weighted `departureBondDamageScore ≥ 65`
(respect weighted 0.45), respect `≤ 35`, **and** at least two Chronicle-surfaced
warnings — and even then the Ori `persists` and becomes a re-discoverable wild
agent; departure is release, not deletion. `evaluateTranscendence` (`:414`)
promotes an agent to **elder** only when a flourishing life-arc is complete
(life-stage `legacy`, all primary threads `integrated`, at least four distinct
thread kinds, flourishing `≥ 85` measured against the agent's _own_ values),
re-parenting it to the Ancestor Grove on the permanent Lachesis cognition tier
as a mentor. `evaluateDeath` (`:521`) is the rarest path and is hard-gated: it
returns `blocked-minor-protection` for any minor-coded agent and
`blocked-unsanctioned-cause` unless the cause is one of three sanctioned kinds
(`isSanctionedDeathCause`, `:751`). A sanctioned death freezes the Ori (it
accepts only memorial annotations), emits weighted **grief**
`RelationshipChanged` writes into every living relation's Ori, queues a Yemaya
remembrance render, and mutates **no lineage edges** — the deceased remains a
permanent ancestor node. The Yemaya job (`buildYemayaRemembrance`, `:731`) is a
queued, idempotent three-stage pipeline: `book-of-ori-keepsake`,
`memorial-reel`, `grove-memorial-placement`. `evaluateAncestorGrove` (`:598`)
renders the lineage DAG as a **walkable** graph of placed actors and propagates
an elder's values and stories to its mentees. A frozen Ori is still fully
readable — freezing stops the life, not the record.

## The passport — identity made portable

When an Ori incarnates into another Oshun realm, the full biography stays here,
authoritative, and the [Aye Bridge](./aye-bridge-cross-game-incarnation.md)
mints a **passport** — `OriPassportInputSchema`
(`libs/contracts/src/v6/ori-passport.ts:68`), a signed, governed envelope
carrying the identity core, provenance bundle, personality model, current ranked
values, a _destination-specific_ capability profile, and the bond ledger. Its
`superRefine` enforces internal consistency (`identityCore.oriId === oriId`, the
destination profile matches the declared realm, and `expiresAt > issuedAt`), and
the outer `OriPassportSchema` wraps it as an `ori-passport-mint` job with an
idempotency key. The destination holds only the passport and writes an
`IncarnationReturned` journal back — deeds and consequences — which appends to
the home log like any other life-event, so a stint in a V4 raid becomes a
permanent, ranked part of who the Ori is. Identity is authored once, lived
everywhere, and remembered here.
