Settings and admin
Which setting wins
The same setting can exist in several places. Resolution, first match wins:
- Campaign settings: the Settings 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.
Blank fields name the startup value or inherited model where available. A blank story model follows an endpoint that lists exactly one chat model; multiple models need an explicit choice. Blank image models mean no pictures. A blank utility model uses the storyteller.
The admin panel
Seven tabs: Server settings, Campaign plugins (world packs), Addons, Users, Usage, Reports and Server log, the server's own console kept in memory, so a turn that failed can be read from the browser. Addons are separate programs extending importers, map generation or board views; world packs reskin a setting. See Addons. 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 server's rolled-stat rule: keep the first pool, reroll below a chosen total, or reroll freely. Each campaign can inherit or override it. |
| 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. |
| Player agents | Receiver addresses, receiver testing, and Allow poll links for hosted agents; poll links are off by default. |
| Storage | Disk usage and cleanup controls. |
| 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, Player agents 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.
Saving and service status
A save bar follows the settings page, says when changes are unsaved, and offers Save or Undo. Test buttons can check the draft before saving. The section row's status lamps distinguish working, not answering, not set up and switched off. Saving admin settings is separate from the table settings that save as you change them.
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 | None selected | Choose a listed model; blank uses the endpoint's sole chat model, if it has exactly one. |
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 | No image model selected | OpenAI-compatible images; select a model before pictures run. 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; model selected from its list | 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; no model selected | Speech-to-text for push-to-talk and transcription. Blank uses a service's sole listed model; choose explicitly if it lists several. |
STT_OPENAI_MODEL | None selected | Paid OpenAI dictation model; without a selection OpenAI is not used for 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 | none | A registry of campaign plugins to browse; none is built in. The Admin field wins, and off there browses nothing. |
ODM_MODEL_CATALOG | on | off stops the daily models.dev catalog refresh; the snapshot and cached catalog still work. |
ODM_ADDONS, ADDON_REGISTRY_URL, ADDONS_DIR | on, project list, data/addons | Addon availability, list and package storage. |
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.