The
apps/hathor/area: the runnable applications of the Hathor worldbuilding-and-narrative domain — REST APIs for the world model and narrative graph, a background simulation worker, two Veilborn game-engine services, a React authoring workbench, and a V2 narrative-content source module.
What this area is#
Hathor is Oshun's worldbuilding / interactive-narrative domain. Where the
libs/hathor/* packages hold the reusable engine and persistence logic, this
apps/hathor/ directory holds the seven deployable applications that
surface that logic: HTTP services, a worker, a single-page authoring UI, and a
content manifest. Every project here carries the scope:hathor, type:app Nx
tags, and the services lean on the shared Hathor libraries — @hathor/database
(Prisma), @hathor/simulation, @hathor/event-handlers,
@hathor/lore-compiler — plus the platform's @lilith/fastify-core /
@lilith/service-lib service scaffolding and @oshun/event-bus.
The applications split into three functional clusters. The worldbuilding
backbone is @hathor/world-api (Git-like versioned world-model store with
cross-domain event subscriptions) and @hathor/narrative-api (story graphs,
quests, dialogue trees), both Hono services persisting through
@hathor/database, fed by @hathor/simulation-worker, which runs
economy/politics/culture/scenario simulations off a job queue. The authoring
surface is @hathor/workbench, a React/Vite SPA for editing worlds,
characters, factions, timelines, and locations, plus @hathor/studio-web, the
source-of-record manifest for V2 narrative content. The game services are
@hathor/veilborn-core and @hathor/veilborn-strategy — two large TypeScript
engines for the "Veilborn Chronicles" tabletop-RPG/wargame and its strategic
"Veil War" mode.
The two clusters are deliberately different in shape. The
worldbuilding/authoring services are thin HTTP/UI layers over persistence and
simulation libraries; the Veilborn services are the opposite — tens of thousands
of lines of in-service domain logic (apps/hathor/svc-veilborn-core/src alone
is ~42K lines across combat, cards, world-gen, awakening, etc.) wrapped in a
comparatively small Fastify surface. Both patterns are real and implemented; the
entity blocks below are honest about which is which.
How it fits the wider system#
@hathor/workbench is the human front door: it calls into the Hathor APIs over
HTTP (its src/api/client.ts targets VITE_API_BASE_URL, default /api) to
manage worlds and their entities. @hathor/world-api is the persistence and
event hub — it subscribes to cross-domain events via @oshun/event-bus and
projects them into the world graph (@hathor/event-handlers).
@hathor/narrative-api owns the narrative structures (story graphs, quests,
dialogue) that the V2 game consumes once compiled. @hathor/studio-web defines
the contract for that V2 handoff: narrative source lives in Hathor and is
emitted as compiled artifacts under V2/ue/Content/Generated/ via
@hathor/lore-compiler, never authored directly in the Unreal editor. The two
Veilborn services are more self-contained game backends that share the same
@lilith/fastify-core runtime and Hathor scope but stand on their own engine
code. Walk the "used by" edges on any node below to see exact consumers.
Entity catalog (7)#
The 7 tracked Nx projects in hathor, each a code-linked entity node — package, type, source path, declared targets, and its internal dependency graph (depends-on / used-by, resolved from the package manifests, §6/§8), read from the project graph. Grouped by architectural layer; walk the dependency links to travel the system. 7 of these carry an authored deep-dive (what / why / how it fits); the rest are generated scaffolds awaiting one.
service (2)#
Veilborn Chronicles - Core game engine for tabletop RPG and wargame
The core game engine for "Veilborn Chronicles," a tabletop RPG and wargame
(apps/hathor/svc-veilborn-core, layer:service, default port 8080). This is
a large in-service engine — ~42K lines across src/ — with deep domain modules:
combat.ts (hex-grid tactical combat with axial/cube coordinates, a "Tide
Initiative" turn system, and Impulse/Flow/Surge/Torrent action economy),
cards.ts (~4K lines of card/deck/attunement/trade logic), plus world-gen.ts,
awakening.ts, multiplayer.ts, social.ts, veylmaster.ts, wargame.ts,
territory-control.ts, combat-ai.ts, character-creation.ts,
database-schema.ts, and more, each with a matching integration test under
src/__tests__/integration/. The modules are pure-logic engines exporting
factory functions (createBattlefield, createCombatant, createCardInstance,
…) exercised directly by the tests. The HTTP service itself (src/app.ts via
@lilith/fastify-core) is deliberately thin: it currently exposes /,
/health//ready//live, and a /metrics endpoint (JSON + Prometheus text),
and tracks request/session counters — it does not yet mount the game modules as
REST routes. So: the engine logic is extensively implemented; the service's
public HTTP surface is minimal.
Veilborn Chronicles - Strategy game engine for The Veil War mode
The strategy-game engine for Veilborn's "The Veil War" mode
(apps/hathor/svc-veilborn-strategy, layer:service). Like core it is a large
implemented engine (~36K lines) but, unlike core, it does mount real REST
and WebSocket routes. src/app.ts (buildServer) wires @lilith/fastify-core
with @fastify/websocket, @lilith/service-lib auth, a RealtimeManager for
multiplayer sync, a data-access layer (createDataAccess with
serializeGameState/deserializeGameState), and five sub-game route groups:
eternal-game, grand-campaign, resonance-wars, temporal (echoes-of-fate), and
weave-conspiracy. Each is backed by a genuine engine — e.g.
resonance-wars/combat-engine.ts (poker-like bluffing tactical combat: intents,
decoys, synergy chains, Yomi pattern tracking),
echoes-of-fate/timeline-engine.ts, eternal-game/influence-engine.ts,
weave-conspiracy/conspiracy-engine.ts, grand-campaign/campaign-manager.ts —
plus per-mode AI under src/ai/ and a balance/tournament pipeline under
src/balance/. Extensively implemented and integration-tested.
unclassified (4)#
A Hono REST service (apps/hathor/narrative-api/src/app.ts, entry
src/index.ts, default port 3003) for the narrative layer: story graphs,
quests, dialogue trees, and narrative validation. It mounts four route groups —
/api/story-graphs, /api/quests, /api/dialogues, /api/validation — over a
service layer that persists through @hathor/database. The persistence mapping
is real and non-trivial: src/services/story-graph.service.ts maps
application-level story graphs/arcs/beats onto Prisma StoryGraph / StoryNode
/ StoryArc tables (e.g. rich graph state stored in the START node's metadata
JSON, connections materialised as arc rows). CORS is locked down to configured
origins (HATHOR_CORS_ORIGINS / CORS_ALLOWED_ORIGINS). Fully implemented,
with Zod schemas under src/schemas/ and tests under src/app.test.ts.
Despite the platform:web tag and "studio-web" name, this is not an
interactive web app — it is a single TypeScript module
(apps/hathor/studio-web/src/v2-narrative-content.ts, ~291 lines, re-exported
from src/index.ts) that is the source-of-record manifest and contract for V2
narrative content. It declares the required narrative surfaces (story,
side_story, krypt, chronicles, dj_story), the compiled-artifact plan
(dialogue banks, sequencer outlines, quest graphs, timelines, etc., all
targeting V2/ue/Content/Generated/... as generatedOnly JSON), the content
packs, and helpers like assertV2NarrativeContentReady /
getV2NarrativeContentCoverage. Per its README the rule it encodes is "compiled
artifact only": narrative source lives in Hathor and compiles via
@hathor/lore-compiler to Unreal, never authored in the V2 editor. Real and
tested (src/v2-narrative-content.spec.ts), but a content-contract module, not
a running UI — the interactive authoring UI is @hathor/workbench.
REQUIRED_V2_NARRATIVE_SURFACES1V2_COMPILED_ARTIFACT_ONLY1V2_NARRATIVE_CONTENT_PACKS1V2_STUDIO_WEB_SOURCE_ROOT1V2_STORY_COMPILER_PACKAGE1assertV2NarrativeContentReady1getV2NarrativeContentCoverage1listV2NarrativeContentPacks1V2CompiledArtifactPlan1V2NarrativeContentPack1V2NarrativeContentSet1V2NarrativeSurface1A React + Vite single-page app (apps/hathor/workbench, platform:web) — the
human authoring UI for the Hathor world model. src/App.tsx defines the routed
shell (Dashboard, Worlds, a per-world WorldEditor, and Characters / Factions /
Timeline / Locations pages under worlds/:worldId/...). It talks to the Hathor
APIs through a typed HTTP client (src/api/client.ts, base URL from
VITE_API_BASE_URL) with per-resource services (worlds, characters, factions,
locations, timeline, dashboard, auth) and uses TanStack Query for data fetching
(see src/pages/WorldEditor.tsx). Components include a FactionGraph,
ScriptEditor, modal/layout primitives, an auth context, and
keyboard-navigation hooks. A real, implemented SPA with tests
(WorldEditor.test.tsx, runtime-services.test.ts).
World Model API for worldbuilding state management, versioning, and queries
The world-model API and event hub (apps/hathor/world-api, default port
3400). A Hono service (src/app.ts) exposing a /api/v1 surface for worlds,
versions, queries, and diff/merge — its README frames it as "World Model API for
worldbuilding state management, versioning, and queries" with Git-like branching
and collaborative diff/merge. The entry point (src/index.ts) additionally
wires cross-domain event handling: it builds an @oshun/event-bus Redis bus
(persistence, retry/backoff, dead-letter config) and registers Hathor event
handlers (setupHathorEventHandlers from @hathor/event-handlers) against a
WorldGraphService. That service (src/services/world-graph.service.ts)
implements the WorldGraphInterface, persisting graph nodes as Prisma Entity
records and edges as EntityRelation records via @hathor/database, with an
honest node-type↔EntityType mapping (e.g. concept round-tripped through
CULTURE + properties.nodeType). Security headers, scoped CORS, rate
limiting, and /ready dependency checks are all present. Fully implemented.
app183workers (1)#
Background workers for running world simulations (economy, politics, culture, scenarios)
A background worker service (apps/hathor/simulation-worker/src/app.ts, entry
src/index.ts, default port 3004, tagged layer:workers) that runs world
simulations off a job queue. createApp wires a JobQueue to a WorkerPool
whose four worker types — economy, politics, culture, scenario — are
configurable via env (ECONOMY_WORKERS, etc.) and exposed over /api/jobs,
/api/workers, /api/stats. The workers are real adapters over the shared
engine: e.g. src/workers/economy-worker.ts drives the actual EconomyManager
from @hathor/simulation (createEconomyManager), running ticks and deriving
GDP / inflation / unemployment / Gini snapshots from market state, honestly
noting that the engine exposes no takeSnapshot so it derives snapshots itself.
Implemented, not a stub.