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 hub's "The Ori Service" and
"Ereshkigal — Endings and Legacy" sections; it sits in The Agent Mind page
group alongside the Moirai kernel,
the cognition stack, and
the Aye Bridge.
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). 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.
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 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 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
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.