A realtime character presence for desktop voice experiences.
Persona is a cross-platform desktop character that gives voice conversations an expressive visual identity alongside your work.
| Platform | Voice output listener | Distribution |
|---|---|---|
| Linux | PipeWire playback-stream capture | AppImage and DEB |
| Windows | WASAPI process-loopback capture | NSIS installer |
| macOS 14.2+ | Core Audio process tap | DMG and ZIP, arm64 and x64 |
Linux requires pw-dump and pw-record on PATH. Windows process-loopback
requires Windows 10 build 20348 or newer. macOS asks once for System Audio
Recording permission.
Each listener is scoped to an automatically detected or user-selected playback process. Persona does not capture the microphone, save audio, produce speech, transcribe content, or send audio over the network.
Click-through lets the avatar float over the desktop, and comes in two forms. On Windows and macOS only the transparent area passes clicks through and the character itself stays clickable, because Electron can keep delivering mouse moves to a window that ignores clicks there. Linux has no such forwarding, so the whole window passes clicks through at once and the character stops responding until the toggle comes back off; treat it as experimental there, since it relies on the X11 input shape and no Wayland compositor has been verified. It starts off everywhere, and stays however you leave it.
Requirements:
- Node.js 24 or newer
- npm
- A desktop session with hardware-accelerated graphics
Persona includes a default character model plus idle and speaking motion. You
can replace the model or add more .vrm and .vrma files from Settings. Other
ignored media under public/assets/ is not loaded unless declared in the
catalog.
To exercise the packaged-library path with the current ignored local test media, copy the provided examples over the active published catalogs:
cp public/assets/library.json.example public/assets/library.json
cp public/assets/manifest.json.example public/assets/manifest.jsonBoth example files are directly usable and also document the complete catalog format. Their media remains test-only: the example manifest deliberately keeps distribution disabled and its license fields incomplete.
Packaged VRM files belong under public/assets/models/; packaged VRMA files
belong under public/assets/animations/. A catalog can declare multiple
packaged models. When default_model_id is null, Persona selects the first
model record as the packaged default.
npm install
npm run demonpm run demo builds the current renderer and launches Persona with normal
automatic voice-output detection.
For a background launch:
npm start -- --backgroundOpen Settings… from Persona's tray menu to manage the character library,
choose the voice audio source, and register MCP. You can preview installed
models and animation actions together, choose the default model, set the
character's initial size, and add your own .vrm and .vrma files.
Until a default model exists, Persona does not create the avatar window or start its voice-output listener. The first imported model becomes the default automatically.
Click-through decides whether the avatar behaves as a desktop pet. It starts off, leaving the window fully interactive. Turn it on and clicks land on whatever sits behind the transparent area around the character. On Windows and macOS the character itself still takes orbit, zoom, and Alt+drag as usual; on Linux nothing in the window is clickable while it is on, and the tray menu reads Click-through (whole window) to say so. Toggle it from the tray menu or from Settings → Appearance; either way the choice is saved and comes back on the next launch. The tray toggle is the way back to an interactive window. Recenter Persona in the same menu is the way back if a pan has carried the character out of view.
Follow the cursor lets the character notice the pointer: the eyes track it as it comes near, the head sometimes joins in, and the character looks away again once it leaves. It starts on, and how near the pointer has to come is measured against the character's own size rather than the window, so it means the same after a resize. The pointer is seen only inside the avatar window, and on Linux with click-through on the window receives no mouse moves at all, so nothing is noticed there. The pointer itself shows an open hand over the window whether or not this is on, since a drag orbits the camera and Alt+drag moves the window.
Persona always provides Idle and Speaking action slots. They begin
without media, so the model keeps its normal pose until you add clips. Each
action can contain multiple .vrma files; uploads receive numbered names such
as idle1, idle2, speaking1, or wave1. Persona chooses a clip from the
action whenever that action runs.
Custom actions include a name, description, and trigger scenario. Persona adds that metadata to its MCP animation tool so a connected agent can understand what the action expresses and when to use it. Imported media and configuration changes stay in Persona's local application data.
Packaged media is immutable. Editing or removing a packaged action creates a user-level override without changing the installed application. Reset packaged actions restores shipped metadata and visibility while leaving user-created actions and uploaded clips untouched.
With Persona running, register its local MCP server:
codex mcp add persona --url http://127.0.0.1:47831/mcpNew Codex sessions can then ask Persona to play an installed animation, show or hide its window, and report whether the local character and voice listener are active. Persona remains a separate desktop application; the MCP connection only exposes its own visual controls.
Persona does not run language models. To use it with a local model stack, open Settings → Voice and select the running app or Linux playback stream that produces assistant audio. Advanced users can supply a cross-platform process pattern, while pipelines that already calculate output levels can use the external-events mode. Any compatible MCP client can use the same animation tools as Codex. See Integrations.
The window intentionally contains no controls:
- Scroll to zoom.
- Left-drag to orbit.
- Right-drag to pan.
- Use your window manager's move gesture to reposition the window.
If a pan or a drag leaves the character or the window out of reach, Recenter Persona in the tray returns the window to its launch corner and re-frames the character.
On Hyprland, Persona also applies floating, pinned, topmost, full-opacity, no-blur, no-shadow, and decoration-free properties. macOS uses an all-Spaces topmost window. Other desktops use the strongest supported Electron window hints.
Build on the operating system you are targeting:
npm run dist:linux
npm run dist:windows
npm run dist:macOutputs are written to release/. Windows needs Visual Studio Build Tools with
the C++ desktop workload. macOS needs Xcode Command Line Tools and macOS 14.2+
SDK support.
GitHub Actions runs the full TypeScript, renderer, native compile, and native
self-test suite on Linux, Windows, and macOS. Prerelease tags shaped like
v0.1.0-beta.0 create native packages and a checksum file, but only after the
asset release gate passes. See Releasing.
The default model and published idle and speaking animations are declared in the packaged library. Other local character media remains excluded from Git and must not be distributed without documented permission. The catalog layout is:
public/assets/
├── library.json
├── library.json.example
├── manifest.json
├── manifest.json.example
├── models/
│ └── <model files declared by library.json>
└── animations/
└── <animation files declared by library.json>
Define each packaged model and animation action in library.json. Action
records carry their public name, description, trigger scenario, runtime type,
and zero or more asset paths. The permanent system-idle and
system-speaking records may have empty asset lists. Mirror every declared
media path in manifest.json, then
complete its license and source fields and set distributionAllowed to true.
Only explicitly allowlisted VRM or VRMA paths should be committed. The release
workflow fails closed when the declared contract is incomplete. Read the
asset license terms.
The dedicated Kimodo settings tab can create reusable motion clips from a
prompt through a separately installed local Kimodo server. Persona converts
the supported SOMA RP skeleton output into a validated .vrma, saves it in a
clip library, and lets any number of actions link to it without duplicating or
owning the file. Failed or interrupted jobs retain safe local artifacts so the
Settings Retry action can resume conversion, installation, or provider polling
without repeating completed work. Local agents can use the same asynchronous
generation flow when the user explicitly enables MCP generation. See the
integration and maintenance documents below before installing the experimental
provider.
npm run check
npm run native:build
npm run native:testThe native listener is required before running Persona from source on macOS or Windows. Linux captures activity through PipeWire and does not build a helper.
Contributions are welcome. Read the contribution guidelines and Code of Conduct before opening an issue or pull request.
More detail:
- Architecture and development
- Codex and integration API
- Kimodo animation generation integration
- Kimodo compatibility and maintenance runbook
- Release process
- Security policy
The source code in this repository is licensed under the MIT License.
Character assets located under public/assets/ are excluded from the MIT
License and are subject to their own respective license terms. See
public/assets/LICENSES.md for details.
