Status: Implemented — architecture matches the delivered code; voice/pipeline components are wired for later milestones
Add a product layer without inserting new blocking dependencies into OpenCode's agent, tool or permission execution path.
flowchart TB
subgraph OpenCode
OC[OpenCode Core / Server]
APP[OpenCode App Store and UI]
end
subgraph WifeCore[Wife Core]
N[Event Normalizer]
AS[Activity Store]
TP[Trigger Policy]
PD[Persona Director]
CR[Character Resolver]
AR[Action Resolver]
PA[Presentation Arbiter]
end
subgraph Desktop[Electron Main]
REG[Character Registry]
TTS[TTS Engine Manager]
SQ[Speech Queue]
WR[Window Runtime Broker]
end
subgraph Renderer
LV[Live2D Renderer]
AU[Audio Runtime]
LS[Lip Sync Controller]
UI[Wife Settings / Character UI]
end
OC --> APP
APP -. non-blocking events .-> N
N --> AS --> TP --> PD --> CR --> AR --> PA
REG --> CR
PA --> WR
WR --> LV
PA --> SQ --> TTS --> AU --> LS --> LV
UI --> REG
Adapts version-specific OpenCode events into a stable Wife event contract. No AI calls.
Maintains semantic snapshots by session:
- current task
- phase
- status
- recent meaningful actions
- changed files
- permission/question state
- completion/error summary
Determines whether an event requires presentation or a persona request. Enforces cooldowns, deduplication and background-session policy.
A lightweight structured-output model request that decides:
- whether to speak
- concise spoken text
- emotion
- gesture
- priority and interruptibility
It does not control model files or tool execution.
Combines configuration layers:
session temporary override
→ window override
→ project binding
→ global default
→ disabled
Maps semantic state/gesture/emotion to a character's available Live2D assets and fallback behaviors.
Coordinates competing sessions and windows. It decides what can be shown or spoken now.
Owns globally registered characters, asset references, validation results and capability caches.
Starts or connects to GPT-SoVITS, checks health, loads voice models and isolates engine failures.
Owns priority, interruption, cancellation and playback order.
Maintains one logical character runtime per window and one speech owner where required. It prevents duplicate speech across BrowserWindows.
Loads the active model and applies:
- base state motion
- one-shot gesture
- expression
- procedural gaze, blink and breathing
- audio-driven lip sync
- OpenCode owns technical truth.
- Wife Core owns semantic activity and presentation intent.
- Character Registry owns registered asset metadata.
- Electron Main owns external processes and cross-window coordination.
- Renderer owns WebGL rendering and actual audio playback.
- Lip sync is derived at the playback endpoint, not in the TTS process.
Prefer small hooks in upstream files:
wifeBridge.observe(event)<WifeProvider>
<ExistingOpenCodeApp />
</WifeProvider><WifeWorkspaceSlot />Do not place substantial persona, TTS or Live2D logic in upstream session reducers, provider code or tool implementations.
Every Wife operation must be non-blocking relative to OpenCode:
void wifePipeline.observe(event).catch((error) => {
wifeLogger.error("observe failed", error)
})Fallback hierarchy:
Persona unavailable → deterministic template
TTS unavailable → speech bubble only
Motion missing → expression/procedural fallback
Character invalid → default character or Classic Mode
Wife runtime failure → OpenCode continues normally