Architecture
Charivo keeps a strict package boundary between orchestration, managers, browser runtimes, and server providers. The rest of this guide walks through that split and how to navigate the repo.
Dependency Direction
The dependency flow is intentionally simple:
App
-> @charivo/core
-> modality packages
-> browser implementations via subpath exports
-> optional server providers behind API routes
In practice:
@charivo/coreowns theCharivoorchestrator, shared types, and event bus- modality packages own stateful feature logic
- browser runtime packages live on subpaths such as
@charivo/tts/remoteor@charivo/realtime/openai - server providers live on
@charivo/server/*subpaths, which keeps credential use and the realtime session bootstrap on the server side — see Server Providers for why most of them are implemented in the modality packages
Lower layers should not take on orchestration concerns from higher layers.
Package Roles
Core
@charivo/core: orchestrator, shared contracts, event bus
Manager Packages
@charivo/llm: conversation lifecycle and message orchestration@charivo/tts: synthesis flow and lip-sync coordination@charivo/stt: recording and transcription lifecycle@charivo/realtime: realtime session state, tools, and in-place session updates@charivo/render: renderer lifecycle, mouse tracking, and visual bridge logic
Each manager wraps a runtime implementation behind a stable manager-facing API.
Avatar Tool Extensions
@charivo/avatar(optional): catalog-constrained avatar expression/motion/gaze tools, instructions, and a result projector, built on@charivo/core's neutralToolRegistration/ToolResultProjectorcontracts. It bridges tool results into both@charivo/realtimeand@charivo/llm, adjacent to but separate from either manager package — see Avatar Control. (Formerly published as@charivo/realtime-avatar.)
Public API Contract
Charivo's public surface is factory-first: components are consumed through interfaces, not concrete classes.
- Pluggable managers, clients, players, transcribers, and renderers are
created via
create*factories (e.g.createRemoteLLMClient,createOpenAITTSPlayer) and consumed through their interfaces (LLMManager,TTSPlayer,RenderManager, ...). Concrete implementation classes such asRemoteLLMClient,OpenAITTSPlayer,ConsoleRenderer,Live2DRendererImpl, and the*Managerimplementations are never exported from a public entry point. Charivois the single top-level orchestrator: it owns the instance lifecycle — wiring managers together viaattach*, holding the event bus, and owningdispose().createCharivo(options)is the factory-first way in, attaching the managers you supply and applying the character last; it returns an ordinary instance, so lateattach*calls work on it just as they do on a hand-constructed one. The class itself remains exported — a partial exception to the rule above — because it predates the factory and direct construction stays supported, not because the factory is limited to up-front wiring.CharivoErrorand its subclasses (CharivoStateError,CharivoTimeoutError,CharivoTransportError,CharivoProviderError,CharivoDisposeError) are a second intentional exception: an error taxonomy to check withisCharivoError/error.code, not a constructible component.- The server provider classes (
OpenAILLMProvider,OpenClawLLMProvider,GeminiLLMProvider,OpenAITTSProvider,GeminiTTSProvider,OpenAISTTProvider,GeminiSTTProvider,OpenAIRealtimeProvider,GeminiRealtimeProvider) are a third intentional exception, exported as concrete classes alongside theircreate*Providerfactories: consumers rely oninstanceofchecks and on provider methods outside the narrow core interface (e.g.OpenAITTSProvider.setModel, absent fromTTSProvider) — a contractpackages/server/__tests__/barrel.test.tspins. Separately, and not a "Node-only" restriction, the factories are also callable directly from a browser viadangerouslyAllowBrowser, letting a local app or test skip standing up a server.@charivo/server/*exports all nine for server use; the two realtime providers are implemented directly there instead of in a modality package (see Server Providers below). - Subclassing
Charivois unsupported; extend it through composition (attach managers, listen to events) rather than inheritance. - The concrete event bus implementation is internal;
CharivoEventBusandCharivoEventEmitterare the contract other code depends on.
Browser Runtime Packages
For most apps, start with remote packages and only use browser-direct packages when you explicitly want local development shortcuts or zero-server behavior.
LLM
@charivo/llm/remote@charivo/llm/openai— also exports thecreateOpenAILLMProviderserver-side provider@charivo/llm/openclaw— also exports thecreateOpenClawLLMProviderserver-side provider@charivo/llm/gemini— also exports thecreateGeminiLLMProviderserver-side provider@charivo/llm/stub
TTS
@charivo/tts/remote@charivo/tts/openai— also exports thecreateOpenAITTSProviderserver-side provider@charivo/tts/gemini— also exports thecreateGeminiTTSProviderserver-side provider@charivo/tts/web
STT
@charivo/stt/remote@charivo/stt/openai— also exports thecreateOpenAISTTProviderserver-side provider@charivo/stt/gemini— also exports thecreateGeminiSTTProviderserver-side provider@charivo/stt/web@charivo/stt/openai-realtime— streaming transcriber; the app supplies the bootstrap function that owns credentials@charivo/stt/gemini-live— streaming transcriber over the Gemini Live websocket; the app supplies the bootstrap function that owns credentials
Realtime
@charivo/realtime/remote@charivo/realtime/openai-agents@charivo/realtime/openai@charivo/realtime/gemini
Rendering
@charivo/render-live2d@charivo/render/stub
Server Providers
Provider packages belong behind your own API routes:
@charivo/server/openai@charivo/server/openclaw@charivo/server/gemini
The LLM/TTS/STT providers under these subpaths are implemented in the
matching modality package (@charivo/llm/openai, @charivo/llm/openclaw,
@charivo/llm/gemini, @charivo/tts/openai, @charivo/tts/gemini,
@charivo/stt/openai, @charivo/stt/gemini) and re-exported here; only the
realtime providers — OpenAI (ephemeral client-secret minting) and Gemini Live
(single-use ephemeral tokens carrying the whole session config) — are
implemented directly in @charivo/server.
That placement is deliberate, not an inverted layering: each of those modality
subpaths also ships a dev/testing browser client that wraps the same provider
instead of duplicating an HTTP client, so the provider has to live where that
client can reuse it — which is why @charivo/server/* is mostly re-exports.
Fresh reviews have misread this twice; it has been examined and upheld both
times, so treat it as settled unless the dev-client path itself is being
removed.
Event Wiring
Charivo intentionally keeps two event contracts:
RenderManagerusessetEventBus(...)TTSManager,STTManager,RealtimeManager, andLLMManagerusesetEventEmitter(...)(optional onLLMManager; wired only when it is attached viaCharivo.attachLLM(...))
This is deliberate.
RenderManagersubscribes to upstream events such astts:lipsync:update,avatar:expression,avatar:motion, andavatar:gaze- TTS, STT, realtime, and LLM managers mainly publish events back into core —
for
LLMManagerthat meansavatar:*-style events from tool result projectors, not conversation events
Do not normalize these contracts unless the public manager API is being redesigned.
Recommended Integration Model
For production browser apps:
- LLM:
@charivo/llm+@charivo/llm/remote+@charivo/server/openaior@charivo/server/gemini - TTS:
@charivo/tts+@charivo/tts/remote+@charivo/server/openaior@charivo/server/gemini - STT:
@charivo/stt+@charivo/stt/remote+@charivo/server/openaior@charivo/server/gemini - Realtime:
@charivo/realtime+@charivo/realtime/remote+@charivo/server/openaior@charivo/server/gemini
Direct browser vendor packages are mainly for development, demos, and testing.
Browser-native packages are a separate option:
@charivo/tts/web@charivo/stt/web
Use them when you want browser-only speech features and can accept browser support differences.
Repository Layout
packages/
core/
avatar/
llm/
tts/
stt/
realtime/
render/
render-live2d/
render-iki/
server/
examples/
web/
companion/
iki-test/
docs/
guide/
history/
images/
docs-site/
scripts/
- root
README.md: project overview and top-level entry points packages/: library packages, publishable except private development adapters such as@charivo/render-ikiexamples/: the two documented reference apps — web puts the LLM/TTS/STT client styles side by side, companion is realtime-only with browser-local character memory — plusiki-test, a private harness for the iki renderer adapterdocs-site/: the site that publishesdocs/guide/docs/guide/: integration guides and package selection helpdocs/history/: migrations, upgrade notes, and implementation historyscripts/: repo tooling
TypeScript Module Resolution
Charivo's public subpath imports require a module resolution mode that honors package exports. Use one of:
moduleResolution: "bundler"moduleResolution: "node16"moduleResolution: "nodenext"