# Hathor — Systems Deep Dive

> 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 reference

### @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`.

### @hathor/simulation-worker

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.

### @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`.

### @hathor/veilborn-core

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.

### @hathor/veilborn-strategy

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.

### @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`).

### @hathor/world-api

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.
