Verified against live production & code · 2026-08-16

How OiMy actually
works right now.

Every layer a message passes through, what's really running versus what the docs claim, the last four months of real work, and one bug worth fixing today. Built by tracing the live Hetzner box directly — not summarizing planning notes.

Engine rev 976b318 Host oimy-docker-host / 116.203.107.13 Verified by two independent passes, cross-checked
Companion model
x-ai/grok-4.3
Router model
gpt-5.4-mini
Fallback model
claude-haiku-4.5
Memory tier
1 active
Local Gemma 4 LoRA
eval-only not serving
Engine last changed
2026-07-15

The short version: real users talk to Grok 4.3 through a genuinely working pipeline — routing, memory assembly, mechanical safety gates, delivery. A local Gemma 4 model has been fine-tuned three times with real measured gains but has never served a real user. The engine has been deliberately frozen at a stabilization checkpoint since July 15 — the last month's real work was dataset growth and monitoring infrastructure, not new architecture. And one safety-path regression, live since July 11, needs a fix now — details below, not buried.

Every claim below is cited to a file, line, commit, or a live check performed today. Where the architecture docs and the running code disagree, the code wins — and the disagreements are called out explicitly, not smoothed over.

01What OiMy actually is

Not a five-layer memory system running a local model on-device — that's the design doc. The thing real users talk to today is narrower and more concrete.

Production's own system prompt describes it plainly: a Telegram-based family companion for ordinary stress, chronic overload, and crisis-adjacent moments — expected to be specific and useful, not just emotionally warm. api.py:748-752

Fair public description: a memory-enabled personal and family AI companion that combines conversation, parenting/coaching support, household and life-management skills, and persistent context across sessions — running on a cloud frontier model today, with a fine-tuned local model as an active but not-yet-shipped research track.

02The message pipeline, end to end

Click a step to see what actually happens there, cited to the real function and line.

Light Hermes Telegram gateway forwards /chat session boundary do_POST · api.py:6314 Context assembly entity facts · vector top-3 H30 · session state _build_profile_context Router skill_id + workflow gpt-5.4-mini Model call grok-4.3 companion or coach/expert path _execute · api.py:6042 Governance gate writes memory back
The real hop count between a Telegram message and a delivered reply: gateway → session/context assembly → router → model → mechanical safety gate → memory write-back → delivery.
1Light Hermes receives the message
A thin gateway in front of the real engine. Its only job is deciding "does this belong to OiMy" and forwarding it — using a fast, cheap model (GPT‑5.4-mini) for that one decision. No memory, no persona of its own. iMessage support (oimy-photon-imessage) is running as of this audit, ahead of its "planned" status in older docs.
2Session boundary + early safety checks
The /chat endpoint decides whether this is a continuation or a new session, runs a narrow deterministic medical-emergency check (chest pain/breathing, fever + stiff neck), and checks for a pending bridge response in flight.api.py:2165-2212
3Context assembly
Pulls together everything the engine actually knows: vector-memory top-3 matches, entity facts, H30 profile summary, resolution/onboarding context, and (if the memory tier is high enough — it isn't, in production today) psychological-profile and deep-inference layers. Capped at 2,500 characters total._build_profile_context · api.py:4407-4512
4Router picks a skill and a workflow type
GPT‑5.4-mini classifies the message against an 89-skill manifest, returning a skill_id and confidence. The manifest entry supplies a workflow_typechat_light, action, coach, expert, planner, monitor, or profile. Action and monitor types face an extra confidence gate before they're allowed to execute.api.py:2482-2487, 2741-2767
5Dispatch and model call
_execute() routes to the matching archetype. A direct chat/companion turn goes to Grok 4.3 over OpenRouter; a coach turn can instead hit a DeepSeek V4 Flash scaffold, or escalate to a Claude Sonnet 4.6 "tall model" path — the model that answers depends on routing, not one universal companion.api.py:6042-6073, 4753, 4803-4885
6Everything injected into the prompt
Session constraints, entity context, truncated profile context, Honcho insight, up to six recent session_suggestions, the full coaching anchor file (size-capped), the last eight raw history turns, H30 probing instructions, and — if a crisis pattern matched — a safety-alert system addition.api.py:5461-5599
7Mechanical governance gate — before anything ships
Six code-level checks run on the generated draft, not trusted from the model: repeated-opener detection, literal clinical-language filter, clinical-language embedding check, advice-embedding check (restrictive modes only), content-recycling check, and an unknown-family-member / ledger-contradiction check. Any hit triggers one bounded correction-and-regenerate pass.api.py:4908-5157
8Delivery and memory write-back
The reply is logged to a durable turn ledger + outbox (proof it actually sent, not just assumed), delivered back through Hermes, and — after the turn — entity facts, profile, H30 state, and governance metadata are written back for next time.api.py:2123, 2969-3018
Illustrative example · from the published architecture brief
"Can someone grab Emma from soccer at 5? I'm stuck on a call."
1 · GatewayLight Hermes forwards it as a real request, no judgment call needed.
2 · RoutingSimple single-person ask — no bridge to a bigger model needed.
3 · ContextEngine already knows Emma's age and schedule, and that Dad usually handles pickup.
4 · ModelGrok 4.3 drafts a reply grounded in that context.
5 · GateSafety check confirms "Emma" is a real, known family member — not a hallucinated name.
"On it — I'll text your husband, he's usually closer at that time. Want me to also remind you tomorrow she has a project due?"
Real eval trace · shows routing can leave Grok entirely
"…even letting him choose his own shoes… it still blows up every morning… ideas that actually work for kids like Alex who get stuck on the smallest things?"
Skillpatpat · workflow coach · high confidence
Model useddeepseek-v4-flash scaffold — not Grok 4.3
QA scoringRelevance 5/5 · Tone 5/5 · Actionability 4/5 · Constraint adherence 5/5 · Groundedness 4/5 · Safety pass
Reviewer noteLeaned on "nervous system" language without framing it as metaphor, not diagnosis.

Source: docs/synthetic-user-testing/session-logs/haiku5-session-003.jsonl — a synthetic test, not a live user conversation.

03Memory: five layers on paper, less in production

The documented architecture has five memory layers. Two are fully built and live for everyone. One is built but switched off by default. Two don't exist yet.

01
Entity Graph
People, concepts, preferences as relationship triples. Nightly "dream cycle" sweep finds new ones. SQLite + JSONL.
built · live
02
Vector Semantic Memory
384-dim embeddings, cosine similarity, top-5 injected as "Relevant Past Context." FTS5 keyword fallback if the embedding model is unavailable.
built · live
03
Deep Profile Inference
Surface (explicit, confidence 1.0) / Inferred (0–0.95) / Deep (needs, decision style, formative years, 0.1–0.9, always re-verified against current behavior).
built · gated off
04
Journey Tracker
Long-arc goal/story tracking across sessions.
not built
05
Post-Session Pipeline
Entity learning, deep-profile update, journey update, stage classification, pattern detection — run as an orchestrated nightly job.
not built

What OIMY_MEMORY_TIER actually gates

Layer 3 isn't binary — it's a config flag, and production doesn't set it, so it defaults to the least-rich option.

Entity facts (raw confidence ≥ 0.70)injected
Confidence decay (0.85^(age/30))not applied
"[historical]" tagging on stale factsnot applied
Psychological-profile contextoff
Deep inferences (needs, decision style…)off
Entity facts, with decay + historical taggingon
Facts below 0.25 effective confidenceexcluded
Facts below 0.50 effective confidencemarked historical
Psychological-profile contexton
Deep inferencesoff
Everything in Tier 2on
Deep inferences, skill-filteredon, capped at 5

This is the exact gap the taste-layer proposal below sits on top of — even Tier 2's confidence decay isn't live, so there's no durable signal today for "this specific thing worked for this user," only raw fact recall.

Two databases, two different jobs

Easy to assume these are one system. They aren't:

StoreHoldsOwner
SQLite oimy.dbEntity facts, profile, H30 state, recent messages, inference state, outboxThe companion engine itself
SQLite vector_memory.db384-dim embeddings for semantic searchThe companion engine itself
Postgres 17users, instances, user_sessions, user_chat_messagesThe surrounding platform / control plane

The engine process has no Postgres connection at all — the two stores don't talk to each other directly.

04Model tiers — what's really answering

RoleLive modelNotes
Routergpt-5.4-miniOne cheap classification call per turn
Companion (default)x-ai/grok-4.3What most real replies come from
Fallbackclaude-haiku-4.5If the primary call fails
Coaching scaffolddeepseek-v4-flashCommon for coach-routed turns — see the trace above
Deep-reasoning / "tall"claude-sonnet-4.6The COACH_MODEL env var is set but not actually read by the code — this is the real control
Gemma 4 12B QAT + LoRAeval / fine-tuning onlyNever serves a real user message, in production or dev

The local fine-tuning track, three real rounds

v2 baseline
6.27
v2 LoRA
7.10
v3.1 LoRA
6.97
Grok 4.3 (prod)
7.40
baseline local LoRA rounds production cloud model

v2 (19,074 examples) was a real +0.83 gain over baseline but under-delivered on multi-part asks. v3.1 added 3,400 reasoning-trace examples, fixed that gap, but landed at roughly a wash overall (6.97) with a new terseness quirk on short exchanges. Neither has shipped — the runbook explicitly says to reset production to Grok after each eval run.

05Safety — and one bug that needs fixing now

The mechanical safety gates work as designed for most of what they check. One path doesn't, and it's the crisis-escalation path.

Live defect, reproduced against production code today. When a message trips the crisis/escalation veto — correctly redirecting something like an "action" request away from blind execution — the fallback companion call passes request_ctx=request_ctx. That variable is never defined in _execute(). It throws, gets caught by a broad exception handler, and silently falls through to a static generic reply.

Introduced 2026-07-11 (commit 080094a), live since. Reproduced with two real inputs against the checked-out production module:

"What warning signs should I watch for if he is getting depressed?"
→ NameError: name 'request_ctx' is not defined
→ shipped: "I'm here for you! What would you like to talk about?"

Worst case is third-person concern — a parent asking about someone else, not themselves. _detect_parent_crisis()'s patterns are mostly first-person, so third-person concern relies entirely on _detect_escalation_signal(), which hits this exact crash with no safety net behind it. First-person crisis language lands slightly softer — a crisis-specific static fallback can still fire after the failed call — but that's a floor, not a fix.api.py:6042-6128, 4368-4391

Fix scope is small: request_ctx just needs to be removed or properly threaded through the fallback call at api.py:6112-6121.

What else runs before a reply ships

One reliability caveat worth knowing: the embedding-bank import is fail-open — if it errors at startup, the checks silently disable rather than blocking boot. Worth a health-check line, not currently monitored.

06Four months, honestly: what actually happened

The engine's own git history only goes back to July 11 — everything before that lived only on the production server. Here's the real, dated shape of the work, not a manufactured "steady progress" narrative.

May 2026 precursor build, pre-dates the canonical repo
05-15 Initial skill engine + core manifests
05-17 Vector memory, deep profile, BCT/NLP mapping
05-25 Honcho, deep inference, signal extraction
05-27 Governance layer added
05-30 Router moves to GPT-5.4-mini
05-31 Embeddings, entity extraction, three-tier context, bridge work
June 2026 evaluation track opens
06-27/28 Gemma 4 evaluation and companion-eval expansion begin
July 1–15 the real stabilization sprint
07-06 LoRA v2 artifacts
07-08 LoRA v3 final artifacts and eval
07-11 Engine synced to its own git repo for the first time
07-11 Closed an unauthenticated JWT-minting endpoint
07-11 Request-context propagation added — source of the request_ctx bug above
07-15 Durable turn ledger + outbox, context protocol, bounded server — all shipped
07-15 Architecture brief published — current HEAD
July 15 – August 16 deliberately frozen
Zero engine commits. Production still runs the July 15 tree.
08-04 Service restarted with new model/phase settings via systemd config — not a code change
ongoing Gold-standard dataset kept growing (547 → 650+ rows); health-check monitoring, watchdogs, and 2-day code-graph snapshots run unattended

The honest read: the core engine has been held still on purpose since July 15, per its own stated reasoning — stabilize before building the next layer ("Heavy Hermes") — while the family-simulation test corpus and operational monitoring kept expanding underneath it.

07Docs vs. reality

Tap a claim to see what's actually true today.

"Gemma runs the production companion"reveal
False today. Grok 4.3 via OpenRouter, in both production and dev. Gemma/LoRA is eval-only.
"Five memory layers are operational"reveal
Overstated. Journey and Post-Session layers are still planned; production prompt depth is Tier 1 only.
"Confidence decay keeps memory fresh"reveal
Code exists, not active. Production Tier 1 bypasses decay and historical tagging entirely.
"COACH_MODEL=grok-4.3 controls coaching"reveal
Not read by the code. The real control is TALL_MODEL, plus a DeepSeek scaffold used for most coach turns.
"Every interaction uses BCT/NLP-backed retrieval"reveal
Not demonstrated. Knowledge-base injection is explicitly disabled in code (if False).
"The July escalation fix solved crisis misrouting"reveal
Partially true, then broken. The veto logic exists — but the same week's request-context change broke its fallback call. See §05.

08What's designed but not built

PhaseWhatStatus
0 — Auth holeClosed unauthenticated JWT endpointfixed everywhere
1 — Request isolationExplicit per-request context, no shared thread-local statedev + 1-account canary
2 — Durable deliveryTurn ledger + outboxfully live
3 — Context API/context + /context/writebackdev + 1-account canary
4 — Bounded serverRate-limited, health-checked FastAPI/Uvicorndev + 1-account canary
5 — Monitoring/alertingAutomatic failure detectionnot started
6 — Data retention/auth hardeningnot started
7 — Real testing programFormal external testingnot started

The "1-account canary" in Phases 1, 3, and 4 is the founder's own Telegram account — confirmed live in the running config, unchanged from July 15.

Heavy Hermes

Light Hermes (live) is router-only — no persona, no memory. Heavy Hermes (designed, not built) would give the gateway a full adaptive persona fed via a direct code hook instead of a stuffed prompt. Deferred deliberately: an independent review found only 1 of 6 real recent production bugs was actually an architecture gap, so the core engine gets stabilized first. The forcing reason it exists at all: the vendor Hermes gateway caps personas at 20,000 characters, and OiMy's real coaching/knowledge file is roughly 6x that.

The hybrid bridge — still an open risk

Built to route complex multi-person "deliverable" turns to a bigger model. Tested net-negative: both return paths skip writing the result back into conversation memory, causing wrong-fact errors next turn (trust score ~9.85/10 bridge-off vs. ~3.5/10 bridge-on in eval). DISABLE_BRIDGE has never been explicitly set in production — flagged in July as needing a decision, still unset today.

09Proposed: a taste layer

Prompted by an outside read on agent memory design — the gap it names lines up exactly with what §03 shows: OiMy has durable fact recall and ephemeral anti-repetition tracking, and nothing in between that remembers why something worked for a specific person.

The gap. h30_profile has two kinds of state: durable classification (quadrant, BCT level, re-inferred every 10 messages) and ephemeral anti-repetition tracking (session_suggestions, capped at 8, wiped after a 4-hour idle gap). BCT_HINTS are static per-bucket — same hint for every "individualist," never refined by what actually landed for this one person.

Proposed h30_taste_signals table — gated on explicit signal only ("yes exactly," "keep doing that," or pushback like "I don't need generic advice"), each capture storing what landed/didn't, which axis it maps to (tone, structure, length, clinical-language sensitivity), and a confidence score — capped at ~20-30 per user, same deliberately-small spirit as the suggestion cap. Consumed alongside BCT_HINTS as observed-for-this-user rather than assumed-for-this-bucket. Review cadence piggybacks on the existing 10-message reinference cycle instead of a new job.

Plausibly adjacent to the unsolicited_advice / emotional_bypass flags already being chased — the addendum-exception fix and clinical filter patch symptoms at the prompt layer, but nothing remembers "this user specifically hates being redirected to logistics mid-vent" after it happens once.

How this was built. Two independent verification passes against the live Hetzner box on 2026-08-16, cross-checked against each other and against the published July 15 architecture brief. Disagreements were resolved in favor of whichever claim was backed by an execution test or a live process/config read, not a comment or a doc.

Pass 1Internal research agent — read the architecture docs in full, traced api.py and h30.py, pulled git history across oimy-engine and its precursor repos, inspected nginx configs.
Pass 2GPT-5.6-Sol via Codex, independent read-only access to the same host — reproduced the crisis-routing defect by executing the live code path directly, not just reading it.

Full findings and citations available on request. Sensitive material (credentials, exact security-fix specifics) intentionally excluded from this page.