Architecture Overview

Audience: Engine Developer Status: ✅ Ready

This page orients you to the whole system before you dive into any single component: the services and how they cooperate, the process/threading model, the path a keystroke travels, and the codebase layout. The organizing invariant is the engine-vs-content pillar — the engine is mechanism, content is flavor — and it shows up architecturally everywhere: no game concept is enumerated in the wire types, the schema, or the runtime.

Start with Overview for the audience-neutral pitch; this page is the engineer’s map into the rest of the Engine Developer Reference.

The service fleet

TelosMUD runs as a small fleet of cooperating services rather than a monolith, so the simulation scales horizontally.

Plane Service Responsibility
Edge telos-gate terminates telnet/TLS, negotiates GMCP, runs the auth handshake, bridges each session to its world shard over the Play gRPC stream (Edge & Protocol)
World telos-world the simulation — hosts zone shards, each a single-writer actor (Zone Runtime & Actor Model)
Orchestration telos-director the control plane — placement, scope leadership, coordinated reload, scheduled work (Orchestration & Directors)
Auth telos-account accounts, identities, characters, trust tiers, OAuth, signed assertions (Accounts & Auth Internals)
Coordination Postgres / Redis / NATS+JetStream durable state / directory + sessions + leases / event & comms bus

Plus one-shot tools: telos-migrate (schema), telos-seed (load a pack), telos-pull (fetch a content version), telos-botswarm (load testing). Only telos-gate, telos-account, and the OAuth broker are internet-facing; the gRPC mesh and datastores stay private (Deployment).

How a keystroke travels

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

The gate decodes the telnet byte stream into a sequenced InputLine and posts it to the owning zone; the zone’s single goroutine runs the command and emits semantic frames back; the gate renders them for the specific terminal. If the player walks into a zone owned by another shard, the world sends a Redirect and the gate re-dials the stream (the TCP socket never moves) — see Cross-Shard Handoff.

The process / threading model

The core discipline is single-writer per zone: one goroutine owns every entity in a zone and is the only code that reads or mutates it, so game logic needs no locks. Everything off-goroutine (the gate reader, the async saver, the reload bus, peer shards) reaches a zone only by posting a message to its inbox. The same pattern repeats one level up: a director is a single-writer actor over one scope’s state. Blocking I/O (Postgres, Redis, network) always happens off the zone/director goroutine, with results posted back as messages. This is what makes the whole system reason-about-able; the invariants are collected in the Distributed Systems Model.

The engine-vs-content pillar, architecturally

The pillar is enforced structurally, not just by convention:

  • Wire types name nothingCoreStats, Vitals, and Item are maps of content-defined keys (RPC & Protobuf).
  • The schema has no per-stat column — a character is identity columns plus one state JSONB; content lives in ~25 definition tables (Persistence & Durability, Pack Entity Reference).
  • The runtime bakes in nothing — attributes, resources, damage types, abilities, combat profiles, tracks, and trust tiers are all content the engine loads (Abilities & Effects, Combat System); a contentless engine boots and reports zeros.
  • Behavior beyond data is sandboxed Lua (Lua Sandbox Internals).

The payoff: the same engine can host a Diku-style fantasy MUD, a D&D 5e ruleset, or a dice-pool sci-fi game purely by swapping content packs.

Codebase layout

Path What’s there
cmd/telos-* the service and tool binaries (one per role)
internal/world the mudlib — entities, zones, combat, abilities, the Lua runtime, persistence dumps
internal/gate / internal/telnet the edge — protocol, GMCP, the Play stream client
internal/account / internal/web / internal/store auth, the OAuth broker, and the Postgres layer
internal/director / internal/scopebus / internal/commbus orchestration and the event bus
internal/content the pack loader, DTOs, and the embedded demo/core packs
internal/directory / internal/checkpoint / internal/placement Redis-backed leases, checkpoints, and zone placement
api/proto the protobuf definitions (generated *.pb.go is gitignored — run buf generate)
db/migrations the SQL schema
deploy/ the local Dockerfile + compose stacks (production IaC lives in a separate repo — Deployment)

A note for contributors: the deep-dive pages cite file:line throughout so they stay re-verifiable against the code — the source is always the authority, and any stale in-repo *.md should be ignored in favor of it.