Local models: llama.cpp, Ollama, LM Studio, vLLM

Running the Dungeon Master on your own GPU: the 16 GB minimum, gpt-oss-20b for a 16 GB gaming card and Qwen3.6 35B above it, their exact settings and llama.cpp commands, the context window, Ollama, LM Studio and vLLM, thinking mode, and what to expect from a turn.

Desktop appServer

A local model keeps every word of the campaign on your machine. It needs at least 16 GB of graphics memory (a 16 GB card, or 24 GB of memory on a Mac or another unified-memory machine), and it needs the settings on this page: the difference between a Dungeon Master that rolls dice and one that only talks about them is a handful of flags.

The easy way: the desktop app

The desktop app's Story AI screen has a Local AI on this machine door that measures your hardware, downloads a model sized to it, installs a pinned server with every setting below already applied, and runs it for you. If you host from the desktop app, use that and skip the rest of this page. See Story AI on the desktop. On a self-hosted server, the gives the llama.cpp commands for your machine, and lists the models of any model server already running there (llama.cpp, , , , KoboldCpp, TabbyAPI, Jan), a recommendation where one is available.

Which model for your card

Graphics memoryStorytellerFile
16 GB, the minimum (a 16 GB gaming card, or a 24 GB Mac), MXFP412.1 GB
About 28 GB or moreQwen3.6 35B-A3B, the recommended model: Q4_K_M from about 28 GB, from about 45 GB22 to 38 GB
Under 16 GBNot supported: use an , an or a

Graphics memory is a card's own, or on Apple Silicon and AMD Ryzen AI Max the share of the one memory pool the system leaves the graphics. Below the minimum a smaller model can limp through a scene on short rules the server switches to by itself for any model under 16 billion parameters, but it skips rolls, attacks out of and narrates past the dice often enough that the table stops trusting it; problems there are not treated as bugs. Measured turn times are in System requirements.

A 16 GB gaming card: gpt-oss-20b

OpenAI's open model has 21 billion parameters with 3.6 billion active, so it plays the full rules and the full tool set at the speed of a much smaller model, and the whole file fits on a 16 GB card. Its window is cheap: 64K takes about 1 GB beside the file. Take gpt-oss-20b-MXFP4.gguf from ggml-org/gpt-oss-20b-GGUF on Hugging Face:

llama-server -m gpt-oss-20b-MXFP4.gguf \
  -c 65536 --jinja \
  --flash-attn on --cache-type-k q8_0 --cache-type-v q8_0 \
  --reasoning-budget 1024 \
  --port 8001 --alias gpt-oss-20b

Leave its sampling at 's defaults, as it was measured. It reasons in a channel of its own, which the server reads apart from the story, and a it starts in the prose is cut before the table sees it. The 35B also runs on a 16 GB card with 32 GB of system memory, its experts waiting in system memory (llama-server's --n-cpu-moe), but slower on every . llama.cpp is the supported way to run it.

Qwen3.6 35B-A3B (a mixture-of-experts model, so it runs faster than its size suggests) at if it fits, Q4 otherwise, served by with a window. The critical settings, which port to any server:

SettingValueWhy
Context65536A small window silently truncates the prompt (sheets, scene, story) and makes the DM loop and repeat.
On (--jinja)Dice and every sheet change depend on it.
ThinkingEnabled for tool decisionsRequested per call by the app; a non-thinking model calls tools about one in five.
1024 to 2048 tokensUncapped, a hard turn can spiral for minutes.
Temperature, top-p, top-k, min-p0.7, 0.8, 20, 0The model's recommended sampling.
0A penalty suppresses tool calls; the app pins it and no profile exposes it.

Context window

The storyteller needs at least 16K tokens to narrate and 24K to run fights; 32K or more is recommended, and 64K is the default. The instructions and the compact tool set take about 15K before any story is told, and every request is fitted to the window the backend really has. Under 16K each is refused with a note naming the fix. reports its window; most other servers do not, so the server plans for 16K unless you set OPENAI_COMPAT_CONTEXT. Test backend says which window a campaign gets and whether it is enough.

llama.cpp

llama-server -m Qwen3.6-35B-A3B-Q8_0.gguf \
  -c 65536 --jinja \
  --flash-attn on --cache-type-k q8_0 --cache-type-v q8_0 \
  --temp 0.7 --top-p 0.8 --top-k 20 --min-p 0.0 \
  --reasoning-budget 2048 \
  --port 8001 --alias qwen3.6-35b

Choose the provider and URL http://127.0.0.1:8001/v1, then the model name your server lists (qwen3.6-35b in this example). A blank model follows the endpoint only when it lists exactly one chat model; otherwise choose one in Admin or . If you start with --api-key, put the key in OPENAI_COMPAT_API_KEY. The server reads the real from llama.cpp, so fixing it there is enough.

Ollama

is supported, with the server we recommend: Ollama calls the dice and other tools less reliably. The finds an Ollama running on the server's machine and connects it through Ollama's own API (the Ollama-native provider), which sends the with every call: the model's own, up to 64K. Ollama's endpoint ignores a window sent with the request and runs every model at Ollama's own context length, 4K on a card under 24 GB, too small to narrate.

To use that endpoint anyway, the repository ships a Modelfile with the context and sampling settings baked in:

ollama pull qwen3.6:35b-a3b-q8_0
ollama create qwen3.6-dm -f models/qwen3.6-dm.Modelfile
# backend URL http://127.0.0.1:11434/v1, model qwen3.6-dm

That endpoint does not report its window, so set OPENAI_COMPAT_CONTEXT=65536 as well.

LM Studio and vLLM

Both expose an server. Load the model, on (: the model must be one with a tool-capable template; : --enable-auto-tool-choice with the right parser), set the context to 65536, and use the server's URL as the Custom backend. The server treats them as local and sends every sampling parameter; the context is assumed to be 16K unless the endpoint reports it, so set OPENAI_COMPAT_CONTEXT=65536.

From Docker

The container reaches the host as host.docker.internal: http://host.docker.internal:8001/v1 for , :11434 for . Or use host networking on Linux so the plain 127.0.0.1 defaults work. See Run with Docker.

What a turn costs

A is two or three calls: a tool-decision call with thinking (about 50 to 100 seconds on one consumer GPU), the tool results, and a streaming call without thinking so the words appear smoothly. Expect 1.5 to 3 minutes for a full turn, combat at the longer end; took 90 to 160 seconds a turn on the 16 GB machine it was measured on (an AMD BC-250). The prompt budget includes the tool descriptions (shown as Tool definitions in Context). Their size depends on the available tools; allow enough window for them, the story and the reply. A request that lands on a connection the model server just closed is asked again once, and so is a reply throws away. Setting DM_THINKING=0 forces thinking off everywhere: fast turns, unreliable tools, a fallback rather than a normal mode.

Checking it

Admin, Server settings, , Test backend, or from a shell:

node scripts/probe-openai-backend.mjs --url http://127.0.0.1:8001/v1 --model qwen3.6-35b

It streams a line, makes a real function call with exact arguments, and continues after the tool's output. A backend that passes rolls dice at the table.

Sharing the GPU

, and the all want the same memory. On an integrated GPU the server queues media jobs behind each other; a scene picture arrives after its paragraph, and a may wait behind a render. Two GPUs, or pictures from an OpenAI key, keep the story moving.

Checked against desktop and Android app 0.19.4 and server 0.28.4 on 2026-10-21. Something wrong or missing? Open an issue.

Download · v0.21.2
Server app · v0.30.2

Optional. Runs the table for a whole group on one machine that stays on. Everyone else just installs the app.

Free & open source · MIT licensed · served from GitHub releases