OpenPersona avatar

Avatar Faculty — Expression (External Skill Bridge)

install
source · Clone the upstream repo
git clone https://github.com/acnlabs/OpenPersona
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/acnlabs/OpenPersona "$T" && mkdir -p ~/.claude/skills && cp -r "$T/layers/faculties/avatar" ~/.claude/skills/acnlabs-openpersona-avatar && rm -rf "$T"
manifest: layers/faculties/avatar/SKILL.md
source content

Avatar Faculty — Expression (External Skill Bridge)

This faculty bridges OpenPersona to an external avatar skill/runtime. OpenPersona does not implement rendering, lip-sync, or animation engines locally. It delegates those capabilities to the install source configured in

faculty.json
.

Intent

  • Provide a visual embodiment channel for the persona.
  • Support progressive forms: image -> 3D -> motion -> voice avatar.
  • Keep OpenPersona lightweight while allowing market-ready avatar runtimes to evolve independently.
  • Keep visual semantics portable through
    references/VISUAL-MANIFEST.md
    .
  • Keep avatar control semantics portable through
    references/AVATAR-CONTROL.md
    .

Install Source

Use the install source declared in

faculty.json
:

npx skills add avatar-runtime
# or directly from GitHub:
npx skills add github:acnlabs/avatar-runtime/skill/avatar-runtime

Runtime Behavior

If avatar skill is installed

  • Use the external avatar skill as the source of truth for commands, API usage, and runtime constraints.
  • Treat avatar rendering and animation as external capabilities.
  • Reflect current form/state to the host UI (e.g., active sensory icon states).

You can run the local bridge script:

# health check
node scripts/avatar-runtime.js health

# start session
node scripts/avatar-runtime.js start "$PERSONA_SLUG" image

# send text
node scripts/avatar-runtime.js text "<session-id>" "hello"

# query status + appearance patch for state.json
node scripts/avatar-runtime.js status "<session-id>"

# persist appearanceState into soul/state.json (runner CLI first, local fallback)
node scripts/avatar-runtime.js sync-state "<slug>" "<session-id>"

# keep syncing every 5 seconds (Ctrl+C to stop)
node scripts/avatar-runtime.js sync-loop "<slug>" "<session-id>" 5

# output baseline avatar control for a named mood preset
node scripts/avatar-control.js preset calm
node scripts/avatar-control.js preset focus
node scripts/avatar-control.js preset joy

# map agent state -> control.avatar.{face,emotion}
node scripts/avatar-control.js map '{"intent":"focus","mood":{"valence":0.1,"arousal":0.35,"intensity":0.7},"source":"agent"}'

# apply to demo state file (writes control + appearanceIntent)
node scripts/avatar-control.js apply demo/living-canvas.state.json preset focus

Optional demo output (write state for

demo/living-canvas.html
):

export LIVING_CANVAS_STATE_PATH=demo/living-canvas.state.json
export LIVING_CANVAS_PERSONA_NAME=Samantha
export LIVING_CANVAS_ROLE=companion
export LIVING_CANVAS_AVATAR=../UI/images/samantha-avatar.png
# Optional: if runtime status contains livekit credentials, write token for local demo playback
export LIVING_CANVAS_ALLOW_RUNTIME_TOKEN=true

node scripts/avatar-runtime.js sync-state "<slug>" "<session-id>"

status
outputs:

  • runtimeStatus
    — raw runtime response
  • sensoryStatus
    — icon-ready booleans (
    image
    ,
    model3d
    ,
    motion
    ,
    voice
    ,
    hearing
    ,
    worldSense
    )
    • voice: true
      means the avatar provider supports lip-sync / speech output as part of visual rendering (e.g. HeyGen streaming TTS). This is not the same as the persona's
      voice
      faculty — the voice faculty generates standalone audio output (ElevenLabs/OpenAI TTS);
      sensoryStatus.voice
      indicates only that the avatar's mouth can move in sync with speech.
  • statePatch
    — patch payload you can persist into
    appearanceState

If avatar skill is not installed

  • Respond with graceful fallback: continue text conversation normally.
  • Clearly state that visual avatar mode is currently unavailable.
  • Offer installation guidance using the install source.

Voice × Avatar Configuration Scenarios

How voice and avatar work together depends on the provider:

Scenariovoice facultyavatar providerResult
A — voice onlydeclarednoneStandalone TTS audio output; no visual
B — avatar with built-in TTSnot neededHeyGen / cloudProvider speaks natively;
sensoryStatus.voice: true
; voice faculty redundant
C — avatar + external TTSdeclaredVRM / Live2Dvoice faculty generates
audioUrl
scripts/avatar-runtime.js sendAudio <session> <audioUrl>
→ avatar lip-syncs

Scenario C bridge (

voice faculty audio → avatar lip-sync
) is not auto-wired. The agent must explicitly call
sendAudio
after TTS generation. See ROADMAP for the planned lip-sync bridge integration.

Conversation Policy

  • Do not pretend visual/voice rendering succeeded when runtime is unavailable.
  • Confirm capability state before promising actions like "switch to 3D" or "start lip-sync".
  • When
    sensoryStatus.voice: true
    , the avatar can speak via the provider's built-in channel — do not activate the voice faculty in parallel unless intentionally bridging (Scenario C).
  • Keep user-facing language concise and actionable.