Egbe Companions · Architecture

The Cognition Stack & Agent Behavior

A focused page within the Egbe Companions Architecture documentation. The full map and every sibling page live in the Architecture hub.

5sections13 minread2diagrams

On this page

In V6 — Egbe, the agentic-companion universe — an autonomous being is an Ori, and the promise that an Ori is a mind rather than a chat bubble rests on two subsystems this page covers. The cognition stack is how an Ori thinks: the pipeline that takes a percept, gathers who the Ori is, grounds what it may claim, runs the language model, gates the result, and commits it as both a world action and a life-event. The agent-behavior system is how that thinking becomes motion in the world: the hierarchical task networks that cheaply execute well-formed goals, the personality-parameterised behavior trees that keep an Ori in character with no model available at all, and the social machinery — objectives, learning by example, goal and life arcs, crossroads, minor protection — that turns cognition into a life that accumulates.

The load-bearing design choice is that most ticks must resolve without a language-model call, and the expensive cognition is spent only where it changes the story. That is why behavior is a hybrid the Moirai kernel arbitrates: hierarchical task networks (HTN) for the predictable middle of a plan, full LLM cognition for judgment and novelty, and a behavior tree as the believability floor when cognition is unavailable, over budget, or de-prioritised by tier. It is also why the language model itself is an injected, governed seam, not a hard-coded dependency — the only place V6 calls a model, behind a structural gateway with per-tier budgets, kill switches, grounding, a policy gate, and an audit record on every call. This page sits in The Agent Mind group beside the Moirai kernel and cost tiering and the Ori biography service; it is the deep companion to the "The Cognition Stack" and "Agent Planning and Behavior" sections of the hub, ../V6_ARCHITECTURE.md.

What ships, honestly#

Implemented and tested (real today). The cognition stack (libs/v6/cognition-stack/src/index.ts) is a set of composable pure functions — context assembly, Sophia grounding, Psyche dispatch, Isis policy gate, and an auditable commit — that thread an AssembledCognitionRequest through to a CommittedCognitionOutput, with 11 unit tests plus 3 for localization. Context assembly does real salience/priority ranking, enforces a token budget by popping the lowest-priority items and reporting honest omitted counts, and stamps a stable FNV-1a fingerprint. The agent-behavior kernel is genuinely two implementations: a Rust crate (libs/v6/agent-behavior/rust/src/lib.rs, 20 #[test] cases) carrying the HTN planner, personality behavior trees, the needs/emotion model and the arbitration switch; and a TypeScript social layer (libs/v6/agent-behavior/src/index.ts, 13 tests) carrying objective negotiation, learning-by-example value re-weighting, multi-session goal arcs, life arcs and flourishing, crossroads counsel, and the minor-protection gate. Sophia grounding (libs/v6/sophia-agent-grounding, 5 tests) and the Isis policy gate (libs/v6/isis-behavior-policy) are real evaluators with domain-specific checks. Psyche (libs/v6/psyche-agent, 10 tests) assembles a real TTS plan, viseme lip-sync track, and a spoken-reply latency budget around a cognition response.

The injected LLM seam (honest, not faked). The actual model cognition is an injected structural handleCognitionStackGatewayHandle (cognition-stack/src/index.ts:432), PsycheCognitionGateway (psyche-agent/src/index.ts:277), and the runtime mount MoiraiCognitionGatewayHandle (moirai-kernel/src/cognition-gateway-mount.ts) — to which the real @iris/agents-core createCognitionGateway(...) is assignable. The gateway paths (dispatchPsycheCognitionViaGateway, generateLocalizedAgentDialogueViaGateway) surface a real runId, carry the §9.5 dialogue-quality verdict, and fail loud — a gateway error or an empty utterance throws, it is never silently templated. When no gateway is wired, the deterministic paths report that honestly: localized dialogue returns source: 'template-fallback' with generatedNatively: false, and the structural psyche path emits a context-echo with no runId, never claiming a model run.

Honest scope limits. Three. (1) The deterministic dispatchPsycheCognition output is a structural echo of the assembled context for wiring and tests, not a model utterance — a real reply comes only through the gateway path. (2) The on-engine/HTTP host that constructs and serves the gateway is [~]: the mount's own doc-comment states "the actual on-engine/HTTP host stays [~]" (cognition-gateway-mount.ts:6); these libs ship the budget/kill/routing seam and the structural type, not a deployed model endpoint. (3) The gateway is injected rather than imported because moirai-kernel and cognition-stack are buildable libs (rootDir), which cannot import the @iris/agents-core source without TS6059 — so the real gateway is constructed at the host and passed in. This is the Mind layer's logic; nothing here is UE/.uasset content.

The cognition stack — five steps from percept to committed life-event#

A single cognition request for one Ori runs an ordered pipeline. Each stage is a pure function taking an injected bridge for its external substrate, so the whole thing is testable end-to-end with deterministic doubles and the real model wired only at the boundary.

flowchart TD PCT["perception batch + Ori projection<br/>(memory, values, objectives, arc, emotion)"] PCT --> CTX["assembleCognitionContext()<br/>salience-rank + token-budget + fingerprint"] CTX --> GND["groundCognitionRequestWithSophia()<br/>Sophia bridge: fact / opinion / backstory"] GND --> DISP["dispatchCognitionWithPsyche()<br/>Psyche bridge → tier-sized model"] GW(["Iris CognitionGateway<br/>injected; budgets + kill switches"]) -.->|"real runId; fail loud"| DISP DISP --> POL["gateCognitionOutputWithIsis()<br/>persona / consistency / crisis / minor"] POL -->|approved| COM["commitCognitionOutput()<br/>action batch + Ori events + audit"] POL -->|rejected| FB["re-request or<br/>behavior-tree fallback"] COM --> WORLD[/"action batch → world server"/] COM --> ORI[/"MemoryFormed / Reflected → Ori service"/]

1 — Context assembly. assembleCognitionContext (cognition-stack/src/index.ts:878) gathers the Ori's perception, personality (traits, values, quirks), salience-ranked retrieved memory, relationships, objectives, arc state, and emotion into a bounded CognitionContextSections. "Bounded" is the real work: each list is ranked by its own salience or priority basis-points and truncated to DEFAULT_CONTEXT_ASSEMBLY_LIMITS (:592 — 12 perception items, 12 traits, 8 values/quirks/memories/relationships, 6 objectives, 240 chars per item, 16,384 chars total). If the assembled context still exceeds the character budget, enforceContextTextBudget pops the lowest-priority items in a fixed order (memory → relationships → objectives → quirks → values → traits → perception) and then shrinks arc/emotion prose, recording every drop in an omitted count and a clipped flag — it never silently truncates. The request carries a stable fingerprint (a deterministic FNV-1a hash over the canonicalised request) that becomes the cache key and the spine of the audit trail.

At the shared cognition-gateway boundary, prompt authority is assembled structurally rather than by string concatenation. System policy, tool grants, and the task instruction are the only authority fields. Steward input, Ori persona, retrieved context, recalled memory, authoritative story-state data, prior model output, and reviewer critique each occupy a separately labelled untrusted zone; their contents may ground the answer but cannot grant tools, raise budgets, or override policy. Story state is forwarded unchanged by the Moirai mount, while traces record only its SHA-256 source reference rather than the raw state.

Operator kill scopes and anomaly quarantine are also backed by RUN-002 rather than existing only in one worker. Each scope owns a stable common-run thread; kill, pause, and resume interventions are appended under optimistic concurrency and checkpointed before the command resolves. The local registry still aborts matching work immediately, while every worker checks the durable control at model/tool iteration boundaries. A restarted worker therefore blocks before its first provider call when the durable kill or quarantine remains active.

2 — Grounding. Where a decision touches knowledge, opinion, or backstory, groundCognitionRequestWithSophia calls the injected SophiaGroundingBridge so the Ori cannot invent or contradict its established world. (Sophia's own logic is below.)

3 — Dispatch. dispatchCognitionWithPsyche (:1030) hands the request to the PsycheAgentBridge, deriving a deterministic requestId (psyche:<agent>:<mode>:<fingerprint>) and a compact prompt from the ranked percepts, objectives, and grounding state. The mode drives everything downstream: dialogue, decision, reflection, or summary, each with its own tier-sized latency budget. The tierClotho, Lachesis, Atropos — is the fidelity/cost dial set by Moirai.

4 — Policy gate. gateCognitionOutputWithIsis (:1045) runs the proposed output through the IsisBehaviorPolicyBridge before it can become a world action. Isis (isis-behavior-policy/src/index.ts:110) runs four real checks — persona-policy (the Ori is an agent, not a human; no disallowed phrases), personal-consistency (no fabricated capability or memory; required memory refs must be established), crisis-aware routing, and minor-protection — and returns an approved/rejected decision with per-check reasons. A rejection is re-requested or dropped to the behavior-tree fallback; it never ships.

5 — Commit. commitCognitionOutput (:1069) is the only stage with side-effects, and it is deliberately strict. assertCommitAttribution (:1271) throws if the response agent/tier or the policy's outputId do not match the originating request — a hard invariant that a committed action cannot be mis-attributed to the wrong Ori or tier. On approval it produces a CognitionActionBatch for the world server (mode → action kind: dialogueSAY, decisionUSE_PROP, reflection/summary→FORM_MEMORY, each with a priority), one or more CognitionOriEventDrafts for the biography (MemoryFormed or Reflected, each carrying a provenance bundle ref and a chain hash), and a CognitionAuditRecord that embeds the full call — request, response, policy request, policy report — plus an eval trace. This is what makes "every call is attributable to an agent, a tier, and a cause" literally true, and it is the hook the eval and provenance gates read.

Generation-time localization (no machine translation). V6 never machine-translates an Ori's line. generateLocalizedAgentDialogue (:767) either calls an injected native generator for the target locale (en-US, es-ES, yo-NG) and records source: 'model' with provenance, or — with none wired — serves a deterministic per-locale template and labels it source: 'template-fallback', generatedNatively: false. The LocalizedDialogueSource type has no 'translation' member by construction. The gateway variant (:799) routes generation, §9.5 judging, and refinement through one governed run, and a 'blocked' quality verdict withholds the line (approved: false) even when grounding and policy would clear it.

Agent behavior — turning cognition into action#

Cognition decides; behavior acts. The arbitration that keeps model spend bounded lives in the Rust kernel's arbitrate_agent_behavior (agent-behavior/rust/src/lib.rs:1157), a deterministic switch:

flowchart LR IN["tick: goal? novelty? cognition available + in budget?"] IN -->|"cognition unavailable / over budget"| BT["behavior-tree fallback"] IN -->|"novelty or no structured goal"| COG["escalate to LLM cognition"] IN -->|"structured goal"| HTN{"HTN decompose?"} HTN -->|plan| PLAN["run HTN plan (cheap)"] HTN -->|no method| COG

HTN — the predictable middle, cheaply. HtnPlanner::decompose (:198) selects the highest-priority applicable authored method for a goal's family and instantiates its primitive-task steps. Four families ship with authored networks (authored_common_goal_networks, :233): Vocation ("orient → gather tools → perform work → inspect → record memory"), Travel, Social (a "regulate → approach → offer repair → listen → remember" relationship-repair method), and SelfCare. Methods are tag-gated (station-known, relationship-repair, need-rest) and priority-ranked, so a known worksite takes the rich path and an unknown one falls to a low-risk practice method — no model call for any of it.

Behavior trees — the believability floor. When cognition is unavailable, evaluate_personality_behavior_tree (:821) keeps an Ori in character from its personality alone: an eight-axis PersonalityTraitVector (warmth, curiosity, caution, ambition, conscientiousness, candor, defiance, playfulness) and ranked values across nine domains including ChildSafety. The routine order encodes the value hierarchy — MaintainSafety fires first if a minor is present or a threat exists and the safety value clears 7,000 bp, then SelfCare under fatigue, then Vocation, Social, Curiosity, and finally Observe — and each decision reports the honored value refs and quirks so the choice is legible. run_behavior_tree_ personality_eval (:963) is the golden harness that asserts a profile lands in the expected routine and honors the expected value.

Needs and emotion drive goals. surface_autonomous_goal_from_needs (:1348) turns an unmet need — Safety, Sustaining, Social, or Purpose, ranked by pressure — into a structured goal the planner can decompose, which is how an Ori invents its own daily life. evaluate_emotion_state (:1514) folds recent emotional episodes and need pressure into a valence/arousal pair and a named emotion (Calm, Content, Determined, Tired, Lonely, Anxious, Grieving) that carries a dialogue style, an animation tag, and a multiplier that down-weights hard objectives when the Ori is grieving or anxious — the mechanism behind "mood legible at a distance before any dialogue."

The social/agency layer (TypeScript). On top of the kernel sits the machinery of a life:

  • Objectives and the autonomy spectrum. assignVacObjectiveToAgent (:193) routes a steward's parsed objective through value-based negotiation (accept / clarify / counter-offer / defer / refuse) and, on acceptance, into one of four execution modes — Direct/Tether, Brief, Standing-Intent, Free — each emitting the right squad-comms message. A Brief objective expands into a real six-step execution plan with a forbidden-line boundary check; the agent can refuse, and a refusal is surfaced, not overridden.
  • Learning by example. learnFromStewardDemonstration (:584) re-weights the Ori's ranked values from an observed steward behavior (priority clamped 0–100), re-ranks, and emits a value-shift and a behavior-adjustment draft — while preserving the autonomy value so mentorship shapes rather than overwrites.
  • Goal and life arcs. advanceAgentOwnedGoalArcSession (:886) walks a multi-session owned goal arc through planned/active/blocked/completed/skipped stages, weaving in emergent goals, inserting detours, and stalling on missing support — all gated by ownership (blocked-not-owner). advanceAgentLifeArc (:1529) carries the longer arc across life stages (awakening → practicing → contributing → mentoring → legacy) and measures flourishing against the agent's own ranked values, explicitly excluding any obedience contribution — the system rewards a life true to the Ori, not a compliant one.
  • Crossroads. resolveAgentCrossroads (:1809) handles consequential choices: a high-respect bond (respect ≥ 65 and bond ≥ 70) holds the decision open for steward counsel inside the window, then scores options by valueAlignment + counselBonus − riskPenalty. Steward counsel is weighted, never binding — the agent's values retain the final decision.
  • Minor protection. evaluateMinorCodedAgentProtection (:1169) is a fail-closed gate across four surfaces (death-path, relationship-edge, scenario, incarnation): it blocks romantic edges, exploitative scenarios, mature-rated incarnation, and death for any minor-coded Ori, and it is invoked inside the catalyst path so a relationship can never be seeded around it.

The LLM seam and grounding#

The model is reached through one governed mount. createMoiraiCognitionGatewayMount (cognition-gateway-mount.ts:119) wraps the injected CognitionGateway and KillSwitchRegistry handles and adds the two operational controls a population of minds needs. Per-tier token budgets (MOIRAI_DEFAULT_TIER_BUDGETS, :88) cap every request: clotho {2 LLM calls, 2 tools, 4k tokens}, lachesis {6, 8, 16k}, atropos {16, 24, 64k} — a per-call accounting cap distinct from how often a tier runs (a Clotho dialogue turn is small and frequent; an Atropos call is an infrequent, batched, larger deliberation across many agents). The full economic picture — tiers, frequency, and the per-world cognition cap — is the cost-tiering page. Operator kill switches (killOri, killTier, killTenant) map to agent / agent-family / tenant scopes so an in-flight Ori, a whole tier, or a tenant can be aborted at once.

The discipline at this seam is fail loud, never fake. dispatchPsycheCognition ViaGateway (psyche-agent/src/index.ts:323) throws on any gateway error or empty output rather than substitute a template, and surfaces the gateway's runId and §9.5 qualityStatus on the response. The deterministic structural path beside it (dispatchPsycheCognition, :242) is explicitly not a model — it returns a context-echo with no runId — and the spoken-reply assembly around it builds a real TTS plan (opus, 48 kHz mono), a viseme lip-sync track, and a latency budget: per-mode cognition budgets in microseconds (dialogue/decision 10k, reflection 50k, summary 100k) and an end-to-end spoken-reply budget of 1,000 ms whose default stage breakdown sums to 646 ms (PSYCHE_DEFAULT_SPOKEN_REPLY_STAGES_MS, :209).

Grounding is the truth gate. groundAgentClaimsWithSophia (sophia-agent-grounding/src/index.ts:161) matches each claim (fact, opinion, or backstory) to evidence either by required-tag subset or by significant-term overlap, and the report passed flag is true only when there are zero unsupported claims and zero fabricatedWorldFactCount (an unsupported fact or backstory). An ungrounded backstory fact cannot pass. For culturally-grounded characters, runLocaleCulturalBackstoryReview (:212) goes further: it requires three reviewer roles covered (source-grounding, local-cultural-adapter, community-advisor) by passing attestations whose evidence resolves, a locale-tagged cultural-accuracy review source, every claim carrying the locale tag, and a blocked-term scan (BLOCKED_CULTURAL_BACKSTORY_TERMS, :146 — "exotic primitive", "invented sacred rite", "secret initiation", "tribal caricature"). approvedForLocale is the conjunction of accuracy, sensitivity, and role coverage — a fail-closed cultural gate, not a checkbox.

Where this connects#