Skip to content

Overview

Kurt edited this page Jul 19, 2026 · 3 revisions

Overview

Audience: Everyone Status: ✅ Ready

TelosMUD is a distributed, content-driven MUD engine written in Go: the engine supplies only mechanism — the runtime, networking, persistence, and rules primitives — while every piece of game flavor lives in swappable content packs, so nothing about any particular game is hardcoded.

This page is the front door. It explains the one idea everything else follows from, sketches the running system, and points you at the audience-specific reference you actually want.

The pillar: engine is mechanism, content is flavor

TelosMUD draws a hard line between the engine and the content:

  • The engine knows how to run a persistent, sharded world: it accepts connections, parses commands, resolves targets, applies effects, deals damage, saves state, moves zones between servers, and fans events out to scripts. It knows how things happen.
  • The content decides what happens: every attribute, resource, damage type, ability, class, race, room, mob, item, loot table, and chargen step is data authored in a content pack. The engine ships with none of it baked in — even the list of stats and the notion of "level" are content, not code.

Concretely, the world is driven by 23 content definition tables (attribute_defs, resource_defs, ability_defs, combat_profile_defs, damage_type_defs, class_defs, race_defs, track_defs, loot_table_defs, recipe_defs, channel_defs, display_defs, and more) plus the world entities they describe (rooms, exits, mob and item prototypes, resets). Behavior that data alone can't express is attached as sandboxed Lua. The payoff: the same engine can host a Diku-style fantasy MUD, a D&D 5e SRD ruleset, or a dice-pool sci-fi game purely by swapping packs. The History of MUDs traces where this separation comes from, and the Builder Reference shows how you use it.

Who this wiki is for

The service model

TelosMUD runs as a small fleet of cooperating services rather than a monolith, so the simulation can scale horizontally across machines. There are four long-running services, three pieces of coordination infrastructure, and a handful of one-shot tools — all built from cmd/ in the github.com/double-nibble/telosmud module.

Role Binary / component Responsibility
Edge telos-gate Terminates player connections (plain telnet + TLS), negotiates GMCP for rich clients, runs the auth handshake, and bridges each session to its world shard over the Play gRPC stream.
World telos-world The simulation. Hosts zone shards; each zone is a single-writer actor that owns its entities, runs commands and combat, ticks effects, and executes Lua.
Orchestration telos-director The control plane: dynamic zone placement, scope (region/world) leadership, coordinated content pull/reload, and scheduled work such as world-boss spawns.
Auth telos-account Owns accounts, identities, characters, and trust tiers; drives the terminal-native OAuth device flow and issues the signed session assertions the rest of the fleet trusts.
Coordination Postgres Durable state: content packs, world state, accounts and characters, mail, versioning.
Coordination Redis Session routing, presence, placement leases, and session locks.
Coordination NATS / JetStream The message substrate: cross-shard handoff, the scoped event/comms bus, and content-pull distribution.
Tools telos-migrate Applies the SQL schema migrations (db/migrations).
Tools telos-seed Loads a content pack tree into Postgres.
Tools telos-pull Fetches a content-pack version from the external versioned store.
Tools telos-botswarm Synthetic-load generator for capacity and chaos testing.

How a player gets in

A session flows edge-inward. The player points a client at the gate, authenticates once through an external identity provider via a one-click browser link, and from then on the gate relays their keystrokes to the world shard that currently owns their zone. Rich clients additionally get structured game state over GMCP.

flowchart LR
    C["Player client<br/>(telnet / TLS)"] --> G["telos-gate<br/>(edge, session)"]
    G -- "connect: device-code OAuth" --> A["telos-account<br/>(OAuth, tiers, chargen)"]
    A -- "signed session assertion" --> G
    G <== "Play gRPC bidi stream" ==> W["telos-world<br/>(zone shard, single-writer)"]
    D["telos-director<br/>(placement, scopes)"] -. "leases / handoff / reload" .-> W
    W -- "text + GMCP" --> G --> C
    W <--> PG[("Postgres")]
    W <--> R[("Redis")]
    W <--> N[("NATS/JetStream")]
Loading

Step by step: the connection lands on telos-gate; the player runs connect, which starts an OAuth device flow against telos-account and, on success, yields a signed session assertion the gate trusts. The gate then opens the Play bidirectional gRPC stream to the telos-world shard hosting the player's zone, and from there every command is executed by that zone's single-writer actor. Output returns as text (and, for GMCP-aware clients, structured packages). See Edge & Protocol and Accounts & Auth Internals for the full handshake.

The distribution story

Scaling a persistent text world is the engine's hard problem. Four ideas carry it:

  • Actor-per-zone, single writer. Each zone is owned by exactly one goroutine on one world server; every mutation goes through its op queue. No in-zone locks, deterministic ordering, and a clean unit of placement and consistency. → Zone Runtime & Actor Model
  • Cross-shard handoff. A zone (and the players in it) can move between world servers with zero dropped messages and exactly-once semantics via a fenced two-phase protocol — the backbone of scaling in/out and rolling upgrades. → Cross-Shard Handoff
  • The durability ladder. State is checkpointed to Postgres under two guards — a version watermark for write contention and a monotonic ownership epoch that fences a stale copy of a character out of the durable row entirely — trading latency for safety in tiers and letting a crashed shard rebuild from durable state plus prototypes. → Persistence & Durability
  • The scoped event bus. Systems and content couple loosely by publishing events within zone/region/world scopes, which is how scripts react to the world and how the engine fans work to the right owner. → Scoped Event Bus

The invariants these rest on are collected in the Distributed Systems Model, and the control plane that drives placement and coordination is the Orchestration & Directors page.

Content packs in one paragraph

A content pack is a directory tree of YAML (internal/content/packs/<name>/): a pack.yaml manifest, one file per pack-global section (attributes, abilities, channels, loot tables, …), and a zones/ subtree describing rooms, items, mobs, and resets. The loader merges the tree into a single pack that is either embedded for tests, seeded into Postgres, or pulled from an external versioned store and hot-reloaded across shards. Behavior beyond static data is added as sandboxed Lua on def-table hooks and entity triggers. The repo ships a complete example — the demo pack (a midgaard/darkwood/crypt world) — plus a minimal core bootstrap pack. Start at Pack Authoring and the Pack Reference.

Tech stack quick facts

  • Language: Go 1.25, module github.com/double-nibble/telosmud.
  • Service RPC: gRPC with Protocol Buffers, generated via buf (api/proto/telosmud/{common,account,play,handoff}/v1).
  • Data & coordination: Postgres (durable state), Redis (sessions/presence/leases), NATS + JetStream (handoff, event bus, content pull).
  • Scripting: a vendored fork of gopher-lua (double-nibble/gopher-lua, via go.mod replace) adding a per-call instruction-count abort for sandbox safety. → Lua Sandbox Internals
  • Player transport: plain telnet and TLS telnet, with GMCP (telnet option 201) negotiated for structured game data. (MCCP compression, NAWS, TTYPE, and CHARSET are not implemented.) → Edge & Protocol
  • Rich clients: GMCP surface covering Core, Char, Room, and Comm packages.
  • Observability: OpenTelemetry metrics over OTLP/gRPC.
  • Auth: OAuth-only, terminal-native device-code flow — no passwords.

Clone this wiki locally