External Publication
Visit Post

The ClockWork Dark

Hugging Face Forums [Unofficial] June 22, 2026
Source

What’s new (v0.9)

The world is no longer static scenery — it reacts.

  • The reactive world — Doom Clock beats reshape the map: flags, discoveries, rumors, and NPC relocations fire as beats cross. The tunnels open new ground; villagers flee to the square; the notice board pins the Dark’s own bounties.
  • Set-pieces — authored, world-gated challenges you descend into: the tunnel-mouth (a branching underground decision tree with per-node scene art) and the warden barrow at Hollow Hill (learn the older name — or trust the faceless Assistant, who points at the wrong star).
  • The convergence payoff — the older name learned in Hollow Hill sharpens the unmake reckoning at the tower. The narrative spine is complete: tunnels open → descend → Hollow Hill → name the Hollow Crown → carry the older name → unmake the Dark.
  • NPCs move with the Dark — Aldric, Greta, the gate — named villagers relocate as beats fire. Maris does not move.
  • The Forge — Brann Holt’s smithy, station-gated recipes (warded blade, reforged relic), the mundane counterpart to Maris’s oven.
  • The world map — a “known reaches” overlay: a hand-painted overview map above a list of every location, the current one lit, visited ones marked.
  • Cutscenes & dice faces — tunnel entrance reveal, tunnel descent, Hollow Hill arrival, and forge cutscenes wired; the dice toast shows the exact rolled d20 face as a still.
  • Reactive notice board — the board’s face changes as the Dark spreads; bounties pin themselves up as their beat-flags fire.
  • Frontend a11y — Escape-to-close, focus-trap, focus-restore on all dialogs; :focus-visible; prefers-reduced-motion.
  • CI pipeline — pytest, vitest+jsdom, Playwright e2e on every push.
  • 393 backend tests, 19 vitest tests, 48 OKFS concepts.

Architecture

A deterministic engine holds all mechanical truth; two autonomous LLM agents improvise on top; a governance layer reins them in; OKFS feeds them canon; media renders it.

flowchart TB
    subgraph HARD["Hard Engine — engine/game/ (the only authority)"]
        STATE["GameState · dice · combat · crafting · travel<br/>evil_ticker · DoomClock · challenges · contracts"]
        SKILLS["@skill registry — engine/skills/<br/>roll_dice · resolve_combat · craft_item · move_to · confront_darkness"]
    end
    subgraph AGENTS["Two Agents — engine/agents/"]
        DRIVER["Storyteller / Driver<br/>big model · drives world · Evaluator gate + retry"]
        ASSIST["Assistant<br/>small model · unreliable companion<br/>AssistantDirector: when / with-what / how-reliably"]
    end
    subgraph GOV["Governance — engine/governance/ + engine/mcp/"]
        PRE["PRE interceptors — shape the prompt<br/>LoreInject · DoomBeat · EvilPhaseTone · StorytellerMind · AwarenessGate"]
        POST["POST audit — SceneRulesEngine R001-R005<br/>RulesGovernor records LLM overreach"]
    end
    subgraph KNOW["OKFS Knowledge — knowledge/"]
        OKFS["one concept per .md + frontmatter + links<br/>lore · NPCs · items · arcs · runbooks · metrics<br/>content-hashed _index.json"]
    end
    subgraph MEDIA["Media — engine/media/ (graceful degradation)"]
        IMG["ComfyUI images / cutscenes"]
        VOICE["Voxtral TTS / STT"]
    end
    OBS["Oracle — engine/observability/ · /api/metrics"]

    SKILLS <--> STATE
    AGENTS -- "propose, never decide" --> SKILLS
    PRE --> AGENTS --> POST
    KNOW -. "RAG / progressive disclosure" .-> AGENTS
    AGENTS --> MEDIA
    AGENTS --> OBS
    POST --> OBS

The balance we chase: let the AIs run loose enough to surprise ; rein them with the engine + governance enough to stay coherent and fair.


The systems

System What it does Key tools
Deterministic dice / skill engine All randomness is engine-rolled and reproducible. The LLM must call a tool before narrating any outcome. roll_dice, resolve_skill_check
Grounded combat Engine-authoritative d20 to-hit, damage dice, fear/exhaustion, fleeing, defending, and sympathy — the “unmaking” damage that works against clockwork foes. resolve_combat, query_combat_state
Crafting Baking, herbalism, tinkering. Engine consumes inputs, grants output; recipes gate on location & ingredients. craft_item, list_recipes
The Doom Clock Turns evil drift into a story — arcs quiet_life → whisper → march → convergence → consumed, once-only world-sign beats (cog-harvesters, brass scarecrow, vines, the opened tunnels, the tower), and the terminal consumed ending if you never push back. Engagement (rising when you confront the Dark) slows the tick ~40%, but decays — so you must keep pushing. confront_darkness
The reactive world Doom Clock beats reshape the map — each fires declarative effects (flags, discoveries, rumors, NPC relocations) onto GameState. Crossing a beat unlocks new ground, displaces villagers, and gates notice-board postings. The world remembers. apply_beat_effects
Set-pieces Authored, world-gated challenges — the tunnel-mouth (a branching underground descent) and the warden barrow (Hollow Hill — learn the older name or trust the faceless Assistant). Presented by the engine, resolved by the standard challenge system, with per-node scene art and riddles. start_set_piece
NPC movement Named villagers relocate as the Dark spreads — Aldric abandons the forest margin, Greta leaves the shrine, the gate thins. npcs_at reflects it; displaced villagers are marked and wear road-worn faces. Maris does not move. npc_moves effects
The Forge Brann Holt’s smithy off the square — station-gated recipes (mend a blade, forge a warded blade, reforge a relic). The mundane anchor: honest anti-Dark gear, craftable only at the anvil. craft_item (station: forge)
The convergence The approach to the clockwork tower as ordered reckoning beats and the player’s last engine-resolved choice (stand / unmake / walk_away), adjudicated on d20 + engagement vs a progress-scaled DC. Learning the older name in Hollow Hill sharpens the unmake roll. resolve_reckoning
The unreliable Assistant Director Each turn, from trust, your struggle, the evil phase, and how recently it last appeared, decides whether the Assistant shows up, with what (quip / hint / lore / warning / gift), and how reliably (low trust → its advice may mislead). Help feels earned and uncertain , never owed. grant_hint, reveal_lore, change_form, assistant_gift
Ephemeral structured challenges (the novel bit) The Storyteller can compose a rule-bound encounter mid-narration — a skill_gauntlet, decision_tree, puzzle, or dice_table — by handing the engine a declarative spec validated against a fixed schema. The AI supplies structure; the engine adjudicates the outcome. An improvising narrator that can’t cheat its own dice. start_challenge, resolve_challenge
Notice board & contracts Opt-in work in three tempers: mundane (dawn-bread, a tinker’s lost cog), bounty (the wandering scarecrow), and anti_dark (still the harvester — raises engagement). The board reacts to the world — postings appear as their beat-flags fire, with signpost poster art. Rewards are engine-granted on genuine completion. list_contracts, accept_contract, complete_contract
Chance encounters Seeded, deterministic rolls on arrival — from the destination edge’s danger_dc and the evil phase. Yields none (calm), a harmless discovery (engine-granted reward), or an ambush naming a clockwork-tagged foe. query_encounter_foes
The Oracle A slim observability backbone. Every turn — latency, eval score, governance violations, the Assistant’s intervention/gift rate, evil drift — is recorded and rolled into aggregates at /api/metrics, so pacing (the heart of the dread) stays visible. GET /api/metrics
Knowledge at runtime Agents search the OKFS bundle and pull a single concept’s body — progressive disclosure, not 3,000 lines at once. query_knowledge, read_concept

Discussion in the ATmosphere

Loading comments...