← Back to Blog

How Does an AI Dungeon Master Work? Inside Embertold's Agent Architecture

Lorenzo Lorenzo · · 5 min read
How Does an AI Dungeon Master Work? Inside Embertold's Agent Architecture

Building Embertold's AI Game Master was the hardest and most rewarding technical challenge we've faced. Here's what we learned, and how it actually works under the hood.

The Vision

We wanted to build something that feels like playing with a skilled human dungeon master, someone who knows the rules, knows the world, reacts to your choices, and tells a compelling story. Not a chatbot with a fantasy skin. A real Game Master.

The Core Challenge

A good Game Master does many things simultaneously: narrates the scene, voices NPCs with distinct personalities, tracks player inventory and health, resolves uncertain actions with dice, manages pacing, generates appropriate challenges, and maintains world consistency.

Asking a single prompt to do all of this in one shot is a recipe for mediocrity. It does everything, but nothing well. So we didn't build it that way.

The Agent Approach

The Game Master runs as a tool-calling agent built on the Vercel AI SDK, routed through the AI Gateway so we can swap the underlying model (or run different models for different features) without touching application code. Each turn, the model receives a system prompt, the current game context, and a set of specialized tools defined with typed schemas, and it decides which tools to call, in what order, based on what the moment needs:

  • Need to describe a scene? Call narrate.
  • NPC is speaking? Call npc_dialogue, which triggers voice generation.
  • An action is uncertain? Call attempt_skill (or the lower-level roll_d20) and let the dice decide.
  • Player found an item? Call modify_inventory.
  • Entering a new area? Call the scene-image and ambient-sound tools.
  • Need lore context? Call query_lore, up to five questions in a single batch, against our Qdrant-backed vector index.

Each tool is narrow and typed. The agent orchestrates them based on game state and the player's action, and a single turn commonly chains four or five tool calls before it's done.

Stateless by Design

Here's a constraint that shaped a lot of the architecture: each turn is a fresh model call with no memory of previous tool-call history baked into the model's own state. Everything the agent needs has to be reconstructed from our database on every turn: chapter summaries, the current chapter's messages, the character's effective stats, active status effects, registered NPCs.

This has a concrete consequence you can see in the tool design: tools that touch an existing NPC, npc_dialogue, update_npc, take the NPC's name rather than a database ID, because the model has no ID to hand back from a previous turn, only the name it can read from the context we just gave it. It's a small detail, but it's the kind of decision that falls out of taking statelessness seriously rather than papering over it.

The Narration Problem

Early versions had a common flaw: the model would try to narrate everything in one massive text block. Walk into a room and you'd get three paragraphs of description, followed by NPC dialogue, followed by a combat resolution, all in one response.

Real dungeon masters don't do this. They set the scene, pause, let the player react, then continue. We fixed this in the system prompt and the tool contracts themselves: narration goes out in beats, interleaved with dialogue, dice results, and audio, so the turn reads like a conversation rather than a wall of text.

Adventure creators can also define a custom narration style that shapes the narrator's tone. A gritty noir adventure reads differently from a whimsical fairy tale purely through prompt configuration, no code change required.

The Consistency Problem

Models don't naturally track state, and we don't ask them to. We built systems around the agent instead of inside it:

  • Inventory tracking — a structured system updated only through explicit tool calls, never inferred from prose
  • Health and status effects — hit points and timed buffs/debuffs (burning, poisoned, stunned, blessed, and others) tracked in Postgres, factored into every skill check automatically
  • Chapter summaries — when a chapter ends, a summarization pass compresses it into a form that fits future context windows
  • NPC registration — characters are registered once with persistent traits and a voice assignment, then only ever changed through update_npc when they die, turn hostile, or leave the story

The agent doesn't remember. The system remembers for it, and reassembles the relevant slice of that memory into context on every single turn.

What We Got Right

Specialized, typed tools over one giant prompt. Structured state in Postgres over relying on model memory. Paced narration over text dumps. Lore grounding via retrieval over unconstrained generation. A gateway abstraction over hardcoding one model provider.

What Surprised Us

The biggest surprise was how much personality emerges from constraints. By giving the model clear rules about pacing, tool usage, and lore consistency, the stories became more creative, not less. Constraints breed creativity, even for AI.

Building a Game Master is never done. Every session teaches us something. But the foundation is solid, and the stories keep getting better.

Related Posts