Applications · entity catalog

hathor app

Authored subsystem deep-dive for hathor, layered on the code-linked entity catalog — what each system is, why it exists, and how it fits.

authored deep-dive
7entities3layers7deep-dives

On this page

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)#

app

@hathor/veilborn-core

#

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.

buildtestlinttypecheckdevstart
layer: servicescope: hathorowner: @GreyChimp
app

@hathor/veilborn-strategy

#

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.

buildtestlinttypecheckdevstart
layer: servicescope: hathorowner: @GreyChimp

unclassified (4)#

app

@hathor/narrative-api

#

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.

buildtestlintserve
scope: hathorowner: @GreyChimp
app

@hathor/studio-web

#

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.

buildtestlinttypecheck
scope: hathorowner: @GreyChimp
app

@hathor/workbench

#

A 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).

buildtestlinttypecheckdevpreview
scope: hathorowner: @GreyChimp
app

@hathor/world-api

#

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.

buildtestlintserve
scope: hathorowner: @GreyChimp

workers (1)#

app

@hathor/simulation-worker

#

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.

buildtestlintserve
layer: workersscope: hathorowner: @GreyChimp