Settings and admin
Which setting wins
The same setting can exist in several places. Resolution, first match wins:
- Campaign settings: the Setup tab's story fields (text provider, URL, model, key, image backend).
- The admin panel at
/admin, stored in the database. - Environment variables, from the process environment or
.env.server. - Built-in defaults.
Every field in the admin panel shows the resolved environment value as its hint; blanking a field falls back one level.
The admin panel
Five tabs: Server settings, Campaign plugins (installed world packs and the registry), Users, Usage (tokens spent per account and campaign) and Reports. Above them, Guided setup asks the same settings one question at a time. Server settings has these sections:
| Section | Holds |
|---|---|
| Server | Server name, public URL. |
| Accounts | New account sign-ups (with account invite codes when invite-only), who may start campaigns and workshops, paid AI backends, the deletion grace period, and the total under which a 4d6 roll may be thrown again (0 allows no second throw). |
| Text model | Default provider, backend base URL, model name, API key, and Test backend. |
| Utility model | A cheaper second model for summaries, compaction, lore checks and Ask the DM; provider, model, URL, key, and its own Test backend. |
| Images | Default backend, ComfyUI URL and checkpoint (or Z-Image Turbo), FLUX worker URL, OpenAI image model, base URL and key. |
| Speech | The narration server (Kokoro, any OpenAI-compatible speech server, or off) with its address, model, key and default voice, and Test narration; the Whisper speech-to-text URL, and the built-in Whisper, installed on demand. |
| Sound library | Download or reinstall the sound pack, with progress. |
| Voice chat | Enable, transport (media server or mesh), media port, announced address, voice domain. |
| Discord | Client ID and secret. |
| Agent | Claude Code, Codex, opencode or Grok Build as the storyteller. Details. |
| Backup | Create, verify, download, delete and restore archives. Details. |
On a world hosted from the desktop or Android app, the sections the app manages (Server, Accounts, Voice chat, Discord and Backup) and the guided setup are hidden. The About dialog in the account menu shows the server's exact build and whether a newer release is out; the server asks GitHub at most every six hours unless ODM_UPDATE_CHECK=off.
Test backend
The text and utility sections can probe the configured backend the way a campaign uses it: streamed text, a real function call with exact arguments, and the continuation after the tool's output. A backend that passes will roll dice at the table; one that fails the tool step will narrate fights it never starts. The same probe runs from a shell:
node scripts/probe-openai-backend.mjs --url http://127.0.0.1:8001/v1 --model qwen3.6-35bEnvironment variables
Set in .env.server (host install) or .env beside the compose file (Docker). Secrets belong here or in the admin panel, never in code.
Required
| Variable | Meaning |
|---|---|
DB_ENCRYPTION_KEY | The database key. Docker generates one if unset; a host install refuses to start without it. |
Text
| Variable | Default | Meaning |
|---|---|---|
DEFAULT_TEXT_PROVIDER | custom | custom (OpenAI-compatible), local (Ollama native), none, harness (agent program). |
OPENAI_COMPAT_BASE_URL | http://127.0.0.1:8001/v1 | The OpenAI-compatible endpoint. |
OPENAI_COMPAT_MODEL | qwen3.6-35b | Model name as the endpoint knows it. |
OPENAI_COMPAT_API_KEY | Key for that endpoint. | |
OPENAI_COMPAT_CONTEXT | Override the context window in tokens. | |
OLLAMA_BASE_URL, LOCAL_TEXT_MODEL | http://127.0.0.1:11434 | The Ollama-native provider. |
OPENROUTER_API_KEY, OPENROUTER_MODEL | OpenRouter as a backend. | |
UTILITY_TEXT_PROVIDER, UTILITY_TEXT_MODEL, UTILITY_TEXT_BASE_URL | The utility model. | |
EMBEDDING_MODEL, EMBEDDING_DTYPE | Xenova/all-MiniLM-L6-v2 | The story memory model. English only by default; Xenova/multilingual-e5-small with q8 for tables in other languages. Changing it re-reads the story in the background. |
DM_THINKING | 1 | 0 forces thinking off everywhere (fast, unreliable tools). |
LOCAL_TEXT_TIMEOUT_MS, ARC_TEXT_TIMEOUT_MS | 360000, 480000 | Per-call timeouts. |
HARNESS_MCP_URL, HARNESS_CONTEXT | Agent program plumbing; rarely needed. |
Images and speech
| Variable | Default | Meaning |
|---|---|---|
DEFAULT_IMAGE_BACKEND | comfyui | comfyui, openai, mflux-hs, sdnq-hs, harness. |
COMFYUI_URL | http://127.0.0.1:8188 | ComfyUI. |
OPENAI_IMAGE_API_KEY, OPENAI_IMAGE_MODEL, OPENAI_IMAGE_BASE_URL | gpt-image-1 | OpenAI-compatible images. OPENAI_API_KEY is read as a fallback. |
FLUX_WORKER_URL | http://127.0.0.1:7869 | The FLUX image worker. |
TTS_PROVIDER | kokoro | The kind of narration server: kokoro, openai (any server with OpenAI's speech endpoint) or off. |
KOKORO_URL | http://127.0.0.1:8880 | Kokoro text-to-speech. |
TTS_BASE_URL, TTS_MODEL, TTS_API_KEY, TTS_VOICE | OpenAI's address, gpt-4o-mini-tts, alloy | The openai kind of narration server. A blank key on OpenAI itself falls back to the key saved for pictures. |
TTS_CONCURRENCY | 2 | Speech requests sent at once across every table (1 to 8). |
STT_URL, STT_MODEL | http://127.0.0.1:8870, distil-large-v3 | Speech-to-text for push-to-talk and transcription. |
FREESOUND_API_KEY | Lets the ambience fetcher use Freesound. |
Voice, network and platform
| Variable | Default | Meaning |
|---|---|---|
VOICE_ENABLED | 0 | Turn voice chat on. |
VOICE_RTC_PORT, VOICE_LISTEN_IP | 44444, 0.0.0.0 | The media port and bind address. |
VOICE_ANNOUNCED_IP, VOICE_DOMAIN | What clients are told to connect to. Required behind NAT or Docker. | |
ODM_ICE_BROKER_URL | the project's broker | STUN and TURN for mesh voice; off for public STUN only. |
APP_PUBLIC_URL | The address players use, behind a proxy. | |
COOKIE_SECURE | auto | 1 behind HTTPS, 0 on plain http. |
PORT, HOSTNAME | 3005, 0.0.0.0 (Docker) | Where the server listens. |
SQLITE_DB_PATH, CONTENT_DB_PATH, WORLD_PACKS_DIR | under data/ | Where the database, content pack and world packs live. |
WORLD_REGISTRY_URL | the default registry | Another registry, or off. |
ODM_BACKUP_DIR | ~/odm-backups | Where backups are written. |
ODM_SETUP_CODE | generated and printed | The one-time code the first account needs. |
ODM_UPDATE_CHECK | on | off stops the server asking GitHub about newer releases. |
UPLOAD_DAILY_BYTES, UPLOAD_DAILY_FILES, UPLOAD_MIN_FREE_BYTES | 500 MB, 200, 1 GB | Each account's daily upload budget, and the free disk uploads keep. 0 turns one off. |
DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET | Discord sign-in. | |
ODM_APP_ORIGINS | Extra origins allowed for the apps' cross-origin calls. | |
ALLOWED_DEV_ORIGINS | Hostnames allowed to hit next dev from a phone. |
The configuration reference in the repository has the same list with longer notes.