Skip to content
Deploy

Environment

Every variable the kit reads, what it unlocks, and what happens when it is unset.

Every variable this kit reads. Names only — values live in your secret store, and env/README.md in the repository says where each one is.

The list in env/.env.example is generated from what the code actually reads, not from memory. A list maintained by hand goes stale the first time somebody is in a hurry, and a stale list is worse than none: it is read as complete, so the missing key is not looked for, it is assumed not to exist.

The switchboard#

VariableUnset means
LIVEKIT_URLno media server to point clients at
LIVEKIT_API_KEYtoken minting returns 503
LIVEKIT_API_SECRETtoken minting returns 503, and webhooks are refused entirely
REGIONS_JSONsingle-region mode; caller_country is ignored
LIVEGRID_REGIONwebhook events are stored with a NULL region

Control plane and API#

VariableUnset means
UDK_SECRETevery request to the control plane is authorised. Local development only
LIVEGRID_CONTROL_URLthe API cannot reach the control plane; /public/live reports unreachable
LIVEGRID_API_URLthe worker has nowhere to post records
LIVEGRID_INGEST_SECRETingest answers 503 rather than accepting anything
LIVEGRID_DEFAULT_ORG_IDcalls are recorded with org_id NULL rather than dropped
CUSTOMER_JWT_SECRET/public/* cannot verify a customer token
MCP_JWT_SECRETno MCP token can be verified, so every caller is anonymous

UDK_SECRET unset is the one to be careful about. It is treated as local development and the service says so on boot — but nothing stops it running that way in production, where it is a public token-minting API.

The render box#

VariableUnset means
LIVEGRID_RENDER_SECRETthe render service refuses to start, and avatar enrolment claims are refused
LIVEGRID_RENDER_URLthe worker cannot reach the renderer
LIVEGRID_ARTIFACT_DIR, MUSETALK_ROOT, LIVEGRID_FACE_MODELpaths, not secrets — the box will not render without them
GOOGLE_API_KEYthis unit currently has no quality gate

That last one deserves its wording. The renderer runs without it; what stops is the review pass that watches the output for motion. Judging an avatar is a temporal problem — does the mouth track the words, do the eyes blink — and it has already overturned a claim that hand-picked frames wrongly supported. Treat "unset" as "nothing is checking", not as "fine".

The agent#

LLM_PROVIDER, LLM_API_KEY, LLM_BASE_URL, LLM_MODEL, TTS_MODEL, TTS_VOICE, STT_MODEL, STT_LANGUAGE, AGENT_NAME, MIN_ENDPOINTING_DELAY_S, AVATAR_PROVIDER, AVATAR_ID.

AGENT_NAME is the one that produces a silent failure: it is the fleet name start_call dispatches to. A worker registered under a different name joins nothing, and the call simply never gets an agent.

Avatar vendors#

One key per vendor, named on Providers and pricing. A vendor with no key set is still listed — it is only excluded from available: true.

Tuning knobs#

LIVEGRID_TARGET_WIDTH, LIVEGRID_TARGET_HEIGHT, LIVEGRID_FACE_PAD, LIVEGRID_BOTTOM_RAMP, LIVEGRID_SIDE_RAMP, LIVEGRID_JPEG_QUALITY, LIVEGRID_MAX_CONCURRENT.

Every one has a measured default, and the reason each number is what it is lives beside it in render/enroll.py and render/musetalk_renderer.py. Override deliberately, not to see what happens.

Never commit a value#

env/.env.example holds key names. A private repository is not a secret store — it is copied into every clone, every CI runner and every agent worktree.

Up nextHealth and status