Skip to content

About

The Cartyx simulator for simulating a game of Dungeons and Dragons

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

cartyx-sim

An autonomous Dungeons & Dragons 5e session simulator: one AI Dungeon Master and four AI players, each running on local models spread across a home LAN, playing in the Cartyx world.

It exists for two reasons:

  1. Test the lore. Find out how well the cartyx-lore repository (story, NPCs, locations, factions) holds up in a real game, and where it is thin, missing, or contradictory.
  2. Produce watchable recordings. Voice every speaker, show art for every character, and play the session back in a video-call-style web page that can be screen-recorded.

The party are students of Avalon Artificers Academy (Alpharetta), rival school to Axe-Ford Park Adventurer Academy (Brookhaven). The simulation never writes back into cartyx-lore or the real table campaign.

Status: the engine, live-model support, and lore retrieval work (Plans 1, 2A, and 2B). Character generation, art, voices, and playback are not built yet. See docs/status.md for the current state and next steps.

How it works

  • Generate, then produce. sim run plays the whole session first and writes an append-only event log (events.jsonl). Art, voices, the timeline, the lore audit, and the playback page are all derived from that log afterward.
  • The engine owns the rules bookkeeping (dice, checks, saves, attacks, HP, spell slots, conditions, initiative, inventory). The DM model adjudicates everything else. There is no grid.
  • Models act through tools. The DM narrates, voices NPCs, rolls, changes state, starts and ends combat, looks up lore, records invented facts, and ends each beat with hand_off. Players speak, act, interject, or pass. Validators check every response and flag rule violations into the log.
  • Players see only what their characters would. Player prompts get a PlayerView (own sheet, allies' vitals, other combatants by coarse status), never the full game state.
  • Sessions pause instead of crashing. A seat that keeps failing, or a table that stalls, pauses the session (exit code 2) with a logged reason; --resume continues from the log.
  • The engine is a library. core and rules have no network or filesystem access, so they can later be embedded in cartyx-app.

Repository layout

npm workspaces, TypeScript, Node 22.22 or newer.

Path What it is
packages/rules 5e bookkeeping: dice and seeded RNG, checks, attacks, HP, conditions, spell slots, initiative, inventory.
packages/core The director turn loop, event schema, state projection, DM and player tools, validators, scheduler, session clock, and the PlayerView.
packages/models An OpenAI-compatible model client (Vercel AI SDK) with per-seat timeouts and fallback endpoints, plus seat benchmarking.
packages/lore Ingests cartyx-lore markdown, chunks it by heading, resolves each chunk to its Kanka entity, embeds and stores it in LanceDB, and answers the engine's lore lookups.
apps/cli The sim command: campaign loading, the JSONL event sink with session locking, sim run, sim bench, sim index, sim script, and sim audit.
apps/cli/examples/local-campaign An example campaign to copy and edit.
apps/cli/fixtures Scripted sessions that run without any model.
docs/ Status, the operator guide, and the design spec, roadmap, and implementation plans.

Planned but not built: packages/media (Plan 3) and apps/playback (Plan 4).

Quick start

npm ci
npm run sim -- run --campaign demo --fixture apps/cli/fixtures/demo-session.json

The fixture run plays a short scripted scene with no models and writes campaigns/demo/sessions/001/events.jsonl. (campaigns/ is git-ignored.)

To play against real models, follow docs/running-a-session.md. In short:

mkdir -p campaigns && cp -R apps/cli/examples/local-campaign campaigns/avalon
# edit campaigns/avalon/campaign.json: endpoints, model ids, one seat per character
npm run sim -- bench --campaign avalon
npm run sim -- run --campaign avalon --target-minutes 10

The sim command

Run it with npm run sim -- <command>.

sim run

Plays a session and appends every event to campaigns/<id>/sessions/NNN/events.jsonl.

Option Meaning
--campaign <id> Required. A folder under the campaigns directory.
--fixture <path> Play a scripted fixture instead of the campaign's model seats.
--session <n> Session number (default 1).
--target-minutes <n> Target spoken minutes; overrides the campaign or fixture.
--seed <n> Seed for reproducible dice.
--resume Continue an existing session log.
--campaigns-dir <path> Campaigns directory (default campaigns).

Exit codes: 0 ended, 2 paused (fix the cause, then rerun with --resume), 130/143 interrupted by Ctrl-C or SIGTERM (the session lock is released).

sim bench

Checks every seat: whether the endpoint answers, whether it lists the configured model, tokens per second, and how many tool-call trials come back well-formed. Saves a report to campaigns/<id>/bench/<timestamp>.json and exits 1 if any seat fails.

Option Meaning
--campaign <id> Required.
--trials <n> Tool-call trials per seat (default 5).
--campaigns-dir <path> Campaigns directory (default campaigns).

With lorePath and an embed seat configured, sim bench also makes one embedding call, reporting its dimensions and latency.

sim index

Builds or refreshes the lore index from the campaign's cartyx-lore checkout (lorePath in campaign.json): chunks markdown by heading, resolves each chunk to its Kanka entity, embeds it through the embed seat, and stores it in LanceDB under campaigns/<id>/.cache/lore-index/. Prints file and chunk counts and every ambiguous entity name it declined to guess (two Kanka entities sharing a display name), a work item for the lore repository, not a build failure.

Option Meaning
--campaign <id> Required.
--force Rebuild even when the index is fresh.
--check Report freshness; build nothing.
--campaigns-dir <path> Campaigns directory (default campaigns).

A fresh sim run rebuilds a stale index automatically; --resume never rebuilds, and refuses if the lore has changed since the session started. See docs/running-a-session.md §9.

sim audit

Writes audit.md and audit.json into a session's directory: gaps (empty lookups), inventions (linked to the narration each supports), coverage (lore entities actually used), and possible contradictions between narration and retrieved lore.

Option Meaning
--campaign <id> Required.
--session <n> Session number (default 1).
--no-model Skip the checker pass for possible contradictions.
--campaigns-dir <path> Campaigns directory (default campaigns).

A campaign folder

campaigns/<id>/
  campaign.json          name, targetMinutes, endpoints, seats (dm + one per player)
  characters/<pc>.json   one file per party member; each needs a seat under seats.players
  .cache/lore-index/     built by `sim index`, when lorePath and an embed seat are set
  sessions/NNN/events.jsonl
  sessions/NNN/audit.md, audit.json   written by `sim audit`
  bench/<timestamp>.json

Campaign files are plain JSON. Campaign ids are lowercase letters, digits, and dashes. Any OpenAI-compatible /v1 server works for a seat: LM Studio, llama.cpp (llama-server --jinja), or mlx_lm.server. Seat options are temperature, maxOutputTokens, timeoutMs, toolChoice (required or auto), and fallbacks. The operator guide covers each one.

Development

npm test               # vitest
npm run test:watch
npm run typecheck      # the whole repo, plus core and rules without Node types
npm run format         # Prettier
npm run format:check

All three checks (typecheck, test, format:check) must pass before a commit. core and rules are typechecked without Node types to keep them free of Node APIs.

Documentation

Roadmap

Plan Delivers Status
1 Engine core: rules, director, event log, sim run against fixtures Implemented
2A Live models: model client, campaign config, sim bench, sim run on real endpoints Implemented
2B Lore: ingest cartyx-lore, embeddings, sim index, sim audit Implemented
2C SRD import, production prompts, scribe, sim chargen, sim prep Not written
3 Media: ComfyUI art and TTS voices, rendered after the run Not written
4 Playback page for OBS recording Not written

Later: MP4 export, live streaming, and play inside cartyx-app.

About

The Cartyx simulator for simulating a game of Dungeons and Dragons

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages