Skip to main content

Atmee avatar plugin for LiveKit Agents

Bring your own LiveKit voice agent; Atmee renders its avatar into your room: a v1 avatar, a talking head generated from a single portrait, or a v2 avatar (invite-only), which moves as a whole. Works like the other avatar plugins for LiveKit Agents: the avatar joins your room as its own participant, your agent's speech drives its video.

from livekit.plugins import atmee

avatar_id = await atmee.AtmeeAPI().create_avatar(name="Val", image="portrait.jpg")

avatar = atmee.AvatarSession(avatar_id=avatar_id)   # ATMEE_API_KEY in the environment
await avatar.start(session, room=ctx.room)
await session.start(agent=..., room=ctx.room)       # the agent's TTS drives the avatar's video

Installation

pip install livekit-plugins-atmee

Python 3.10+, livekit-agents 1.6.8 or newer.

Prerequisites

  • An Atmee API key (sk_atmee_...), in ATMEE_API_KEY. Create one in the Atmee studio at atmee.ai/studio/api-keys. Keep it on your agent's side; it never goes to a browser.
  • Your own LiveKit project (LiveKit Cloud or self-hosted): LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET — the same variables your agent already uses. Atmee never sees your LiveKit secret: the plugin mints a token for the avatar participant locally and hands only that token to Atmee.

Usage

1. Create an avatar from a portrait

Once, from a script or your backend (see examples/create_avatar.py):

async with atmee.AtmeeAPI() as api:   # reads ATMEE_API_KEY from the environment
    avatar_id = await api.create_avatar(name="Val", image="portrait.jpg")

All it needs is a name and a single portrait. image may be a local file path, raw image bytes, or an https:// URL Atmee can download; .jpg, .png, and .webp are accepted. A portrait-only avatar is render-ready immediately — nothing to wait for. You can also create and manage avatars in the Atmee studio at atmee.ai; any avatar of your account with a portrait works.

2. Render it in your agent

async def entrypoint(ctx: agents.JobContext):
    await ctx.connect()
    session = AgentSession(stt=..., llm=..., tts=..., vad=...)

    avatar = atmee.AvatarSession(avatar_id=os.environ["ATMEE_AVATAR_ID"])
    await avatar.start(session, room=ctx.room)        # before session.start

    await session.start(agent=MyAgent(), room=ctx.room)

start() returns as soon as Atmee's rendering worker acknowledged the start (about a second); the avatar's video and audio tracks appear in the room a few seconds later, published by the participant atmee-avatar-agent. Your agent publishes no audio of its own — the avatar speaks for it, lips in sync.

Options on AvatarSession:

Argument Default Meaning
avatar_id required The Atmee avatar to render.
avatar_version "v1" The avatar's generation, "v1" or "v2": how long start() may wait for it to get ready (see Avatar versions).
api_key, api_url ATMEE_API_KEY, ATMEE_API_URL Credentials and API base. api_url is optional and defaults to production, https://api.atmanity.us; set it only to target another environment.
avatar_participant_identity atmee-avatar-agent Identity the avatar joins with; set it when one room hosts several avatars.
max_duration_seconds 3600 Hard ceiling of the session; also the most it can bill if your agent dies without a trace.
wait_for "initializing" "avatar_joined" makes start() block until the avatar is in the room.
metadata None Free-form JSON stored with the session on the Atmee side.

avatar.session_id and avatar.session_info hold the Atmee session after start(); avatar.on("avatar_disconnected", ...) fires if the avatar participant leaves while your agent is still running.

Avatar versions

Atmee avatars come in generations, and the plugin renders both:

  • v1 — a talking-head avatar generated from one portrait, lip-synced to your agent's speech. The default everywhere, so existing code needs no change.
  • v2 — Atmee's next generation (invite-only): the avatar moves as a whole. The first v2 session after a quiet period can take a few minutes to start. Pass avatar_version="v2": start() then waits up to 5 minutes (7.5 with wait_for="avatar_joined") instead of 1 (3), and while Atmee answers avatar_warming it asks again after the Retry-After it gives. Nothing is billed until the render starts.
from livekit.plugins import atmee

avatar = atmee.AvatarSession(avatar_id=..., avatar_version="v2")
avatar.avatar_version                     # "v2"
avatar.session_info.avatar_version        # "v2", after start()
atmee.SUPPORTED_AVATAR_VERSIONS           # frozenset({"v1", "v2"})

info = await atmee.AtmeeAPI().get_avatar(avatar_id)
info.version                              # "v2": the avatar's engine, as the API reports it
info.ready                                # built, and for v2, serving a take

The avatar's own configuration decides how Atmee renders it: the version is not sent with the start, it sets how long the start may wait. A v2 avatar started as "v1" still renders as v2, but a slow first start may outlast the v1 wait; the error then says to pass avatar_version="v2".

AtmeeAPI.create_avatar() makes v1 avatars only: a v2 avatar also needs a voice and a take built over minutes. Create one in the Atmee studio, or with the Atmee CLI or MCP server, and render it here by its id (atmee.CREATABLE_AVATAR_VERSIONS is frozenset({"v1"})). The version is unrelated to AvatarInfo.kind (conversational | render_only), which says whether an avatar has a voice and persona.

Lifecycle and billing

Billing starts when the avatar sees your agent in the room and runs by the minute. It stops when

  • your agent leaves the room or the room closes (the rendering worker notices and reports the end itself — a crashed agent stops being billed within seconds),
  • aclose() runs — registered automatically as a job shutdown callback; it ends the session and removes the avatar participant from your room,
  • the rendering worker itself dies or loses contact: it proves it is alive once a minute, and a session silent for a few minutes is closed and billed only up to the last proof,
  • or the session reaches max_duration_seconds.

Errors

All API failures raise atmee.AtmeeException with status_code, code (the API's error code, e.g. insufficient_credits, avatar_not_renderable, missing_publish_on_behalf) and message. Subclasses worth handling: AtmeeNoCapacityError (every rendering worker is busy; check retry_after and try again later), AtmeeAvatarNotReadyError (the avatar has no portrait, or a v2 avatar no take, yet) and AtmeeAvatarWarmingError (a v2 avatar was still getting ready, or a start was interrupted, when the start's wait ran out; nothing was billed). avatar_version_unavailable means the deployment renders v1 only.

Examples

  • examples/agent.py — a Deepgram + OpenAI + Silero agent with an Atmee avatar; run with python examples/agent.py dev and open the LiveKit Agents Playground.

  • examples/gpt_live_1_agent.py — the same agent using OpenAI gpt-live-1 (LiveKit's native GPTLiveModel) instead of the STT/LLM/TTS pipeline. Runs delegation="client" by default — gpt-live-1 answers itself, no backend round-trip, lowest latency, backchannels while you talk — with expressive full-duplex instructions. GPT_LIVE_DELEGATION=responses switches to a backend reasoning model (gpt-5.6-luna): smarter and able to speak unprompted, but slower on every turn. Needs livekit-agents[openai] and an OpenAI key with gpt-live-1 access.

  • examples/dispatch.py — helper for the gpt-live-1 example: prints a viewer URL, waits until you've joined, then dispatches the avatar into that room (viewer-first). Run the worker in one terminal and this in another.

  • examples/create_avatar.py — create an avatar from a portrait and print its id.

  • tests/test_live_agent.py — a manual live smoke test: a real GPT voice agent (OpenAI LLM + TTS, silero VAD) with an Atmee avatar in a real LiveKit room, asserting the avatar joins, publishes video, and that its agent-driven audio flows. Skipped unless RUN_LIVE_ATMEE_AGENT=1 and the credentials are set:

    RUN_LIVE_ATMEE_AGENT=1 ATMEE_API_KEY=… ATMEE_AVATAR_ID=… \
    LIVEKIT_URL=… LIVEKIT_API_KEY=… LIVEKIT_API_SECRET=… OPENAI_API_KEY=… \
    uv run --group dev --with "livekit-agents[openai,silero]" \
        pytest tests/test_live_agent.py -m live -s
    

How it works

your agent (livekit-agents) ── plugin ──► Atmee API        (X-Api-Key, https)
        │                                     │
        │  audio over lk.audio_stream          ▼
        └──────────────► your LiveKit room ◄── Atmee rendering worker
                                              joins as atmee-avatar-agent,
                                              publishes video + audio
  1. AvatarSession.start() mints a LiveKit access token for the avatar participant with your LiveKit credentials: identity atmee-avatar-agent, kind: agent, a roomJoin grant for your room, and the attribute lk.publish_on_behalf set to your agent's identity. Atmee receives only that token, never your secret.
  2. It calls POST /v1/avatars/{avatarId}/avatar_sessions with your LiveKit URL and the token. Atmee reserves a session, starts a rendering worker, and answers as soon as the worker acknowledged the start.
  3. The worker joins your room with the token, waits for your agent, receives its audio over the LiveKit data stream (lk.audio_stream, 16 kHz PCM, the standard DataStreamAudioOutput), and publishes lip-synced video and audio on behalf of your agent.
  4. When your agent leaves or the room closes, the worker notices from inside the room and reports the end to Atmee, which stops billing. aclose() removes the avatar participant and ends the session explicitly as well.

Development

uv venv && uv pip install -e . --group dev
uv run pytest -q
uv run ruff check . && uv run ruff format --check . && uv run mypy

Releases are published to PyPI from v* tags by .github/workflows/publish.yml (PyPI trusted publishing).

License

Apache-2.0.

Metadata

Release files for livekit-plugins-atmee 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for livekit-plugins-atmee 0.2.0
File Size Uploaded Provenance Actions
livekit_plugins_atmee-0.2.0.tar.gz 21.8 kB With provenance Details for livekit_plugins_atmee-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for livekit-plugins-atmee 0.2.0
File Interpreter ABI Platform Actions
livekit_plugins_atmee-0.2.0-py3-none-any.whl Python 3 none any Details for livekit_plugins_atmee-0.2.0-py3-none-any.whl

Total release size: 47.3 kB

Release files / livekit_plugins_atmee-0.2.0.tar.gz

Download URL livekit_plugins_atmee-0.2.0.tar.gz
Size 21.8 kB
Tags Source
SHA-256 checksum
How to use checksums
70b2bbe0d061bbad18b9527ab9f14aac2874dbb89f31c2e66973b9d5e04a7f9a
BLAKE2b-256 checksum
How to use checksums
b2399cc643e32ac4b718194786e3ba919278a10040a4d57d74a3773c1152474a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Release files / livekit_plugins_atmee-0.2.0-py3-none-any.whl

Download URL livekit_plugins_atmee-0.2.0-py3-none-any.whl
Size 25.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b826ddc9c27b7ae329c7c9a25ea3d49e2b5895f0921e53aed31910116e2723fb
BLAKE2b-256 checksum
How to use checksums
4e84419756d4ba71e24518a07063268d78ba6b998c2f0015f9067da793838578
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

Security for livekit-plugins-atmee 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for livekit_plugins_atmee-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page