Systems Architecture

Fate's Edge is a system of systems: a tabletop ruleset, an LLM-driven Game Master built on top of it, a real-time transport fabric connecting a dozen client surfaces to that GM, and an optional voice pipeline layered on top of all of it.

The full write-up lives in our private architecture doc (companion to fates-edge-ai-gm-bot's DESIGN.md) — this page is the map, not the territory.

Want the "why," not just the "what"? Design-decision write-ups and the reasoning behind bigger architecture calls go up on the dev blog as they happen.
┌─────────────────────────────────────────────────────────────────────┐
│  Layer 4 — Voice: Chatterbox (TTS) → voice-adapter → RVC (optional)  │
├─────────────────────────────────────────────────────────────────────┤
│  Layer 3 — Clients: web · desktop · terminal · Discord · Roll20 ·    │
│            Foundry · Python CLI/GUI                                  │
├─────────────────────────────────────────────────────────────────────┤
│  Layer 2 — Transport: socket server (Socket.IO + plain WS, rooms)    │
├─────────────────────────────────────────────────────────────────────┤
│  Layer 1 — AI GM Bot: driver-agnostic LLM orchestration, tag DSL,    │
│            adventure state machine                                   │
├─────────────────────────────────────────────────────────────────────┤
│  Layer 0 — Rules Engine: d10 pool, Outcome Matrix, Position, SB,     │
│            Boons, Fatigue, Obligation, Timers                        │
└─────────────────────────────────────────────────────────────────────┘

Layer 0 is a formal system the game defines and the software encodes. Layer 1 is the only layer that talks to an LLM at all — everything from Layer 2 down has no idea an AI is involved. A human GM running the same socket server, web client, and voice pipeline gets identical infrastructure. That separation is deliberate, and it's why every layer above Layer 0 is genuinely optional.

Layer 0 — Rules Engine

A deterministic d10 pool system: Outcome Matrix, Position, Boons, Fatigue, Obligation, and Timers. No hidden GM logic, no opaque heuristics — anything the AI GM decides, a human GM (or a script) could decide the same way from the same visible state.

Layer 1 — AI GM Bot

Driver-agnostic LLM orchestration over an adventure state machine, communicating exclusively through the tag-based GM protocol below. Swapping LLM providers, or removing the AI entirely, doesn't touch layers 2–4.

Tag DSL / GM Protocol

Every GM action — scene transitions, skill check outcomes, state changes — is expressed as a small, typed, test-covered directive rather than free-form text, emitted inline in narration and parsed out by modules/commands/process-tags.js.

The set is 24 directives (25 spellings — ADD is an alias of APPLY) for the entire game. They sort into four groups, and the first three — the whole resolution system — account for eleven of them.

The roll

DirectiveDoes
[CALL FOR ROLL "what" Attr+Skill DV n Position "note"]Asks a player to roll. Does not resolve it.
[ROLL "what" Attr+Skill DV n Position]Rolls for an NPC or the world.
[SET DV n]Sets difficulty. 2–5; above 5 is a defect.
[SET POSITION name]Dominant / Controlled / Desperate.

The clock

DirectiveDoes
[TIMER "name" segments "what happens"]Starts a clock. Legal sizes are 4, 6, 8, 10.
[TICK TIMER "name" n]Advances one.

The economy

DirectiveDoes
[ADD SB n] / [SPEND SB n]The GM's Story Beat pool.
[APPLY HARM|FATIGUE|BOON|OBLIGATION|CORRUPTION|LEASH who n]Every per-character track, through one verb.
[ENCOUNTER START "name" type] / [ENCOUNTER RESOLVE clean|partial|miss "notes"]Frames and closes an encounter against the Outcome Matrix.

The table state

The remaining thirteen are bookkeeping — NPC CREATE, NPC CAST, NPC LOCATION, FACT, REVEAL, HIDE, SCENE COMPLETE, MOOD, CROWN, DRAW, TOKEN MOVE, TOKEN REMOVE, LOOKUP RULE — recording who is present, what is known, and where things are. This is the group that grows with content rather than with rules.

Notice what isn't here. There is no [CRAFT], [SIEGE], [TRAVEL], [RITUAL] or [MASS COMBAT] directive, and all of those are fully supported. They didn't need one: crafting, travel, downtime, magic and warfare are each a roll that fills a clock and resolves on the Outcome Matrix. An army is a Follower with a Capability and two clocks; a general's order is an ordinary roll filling an objective by two segments, one, or none. Adding the whole warfare module cost this protocol zero new verbs and its test suite zero new cases.

That is the practical payoff of a self-similar ruleset: the protocol's size is proportional to the number of things the game is (four), not to the number of things it can do. Which gives contributors a heuristic worth applying before opening a PR:

If your extension needs a new tag verb, you have probably not found a gap in the protocol. You have probably invented a mechanic you didn't need. Check first whether the thing you want is a roll, a clock, an outcome, or a piece of table state wearing a costume.

Extensions to the narrative surface — new hooks into world state, better ergonomics for things the protocol expresses clumsily — are genuinely welcome. See Ways to Contribute, and the design write-up for the longer argument.

Layer 2 — Transport

A socket server (Socket.IO plus plain WebSocket, room-based) that gives every client surface — web, desktop, terminal, Discord, Roll20, Foundry, Python — identical real-time event access to a session, regardless of which GM (human or AI) is running it.

Layer 3 — Clients

Web client, desktop client, terminal (ANSI) client, and bridges into Discord, Roll20, Foundry, and a Python CLI/GUI. Each one only needs to speak the room protocol from Layer 2.

Layer 4 — Voice Stack

Chatterbox (TTS) → voice-adapter → RVC (voice cloning), fully optional and toggleable independently of everything else.

Repositories


Discuss this page