The Curator System

Overview

The curator is the AI layer that manages your settlement's cultural direction. It sits between you (the patron) and your elves, translating high-level artistic vision into concrete settlement decisions: who does what, what gets built, when to hold a revel.

Elf Revel uses a three-tier intentionality model:

  1. Patron (you) -- provides taste, values, and broad artistic direction via ArtisticDirection settings and direct messages.
  2. Curator (AI advisor) -- reads the settlement state and issues CulturalCommands. Two implementations: a rule-based DummyCurator (always available) and an LLM-backed LlmCurator (native only, uses claude CLI).
  3. Elves (autonomous agents) -- execute tick-level behaviors: gathering, building, composing, attending revels. They have their own needs, aesthetics, and relationships.

The human has taste, the AI has hands, the elves have lives.

How It Works

The CulturalAdvisor Trait

Every curator implements the CulturalAdvisor trait, which defines three core methods:

MethodPurpose
consult(world)Produce a list of CulturalCommands based on current game state
consult_with_message(world, message)Same, but with a player-typed message for context
should_consult(world, events)Decide whether the curator wants to run this tick

Two additional methods handle forest-clearing tracking (on_forest_cleared) and UI display (last_reasoning).

When the Curator Is Consulted

The default cadence is once per game day (every 100 ticks). The should_consult method fires at day boundaries -- when tick / DAY_LENGTH changes.

The LlmCurator extends this with event-driven triggers. It will also consult when:

EventCondition
RevelEndedAlways
ArtCompletedAlways
InspirationCrisisAlways
ResourceLowWhen amount < 5
SpiritStateChangedWhen spirit enters "Anger"

It also returns true immediately if a pending LLM result has arrived from the background thread.

The CulturalCommand Enum

When consulted, the curator returns a Vec<CulturalCommand>. Each variant maps to a concrete game action:

CommandFieldsEffect
AssignRolename: String, role: ElfRoleSets an elf's workshop assignment. Roles: Gatherer, Builder, Composer, Unassigned
SetResourcePriorityVec<ResourceType>Reorders the settlement's gathering priority. Types: Food, Wood, Stone, FineWood
QueueBuildkind: BuildingTypeAdds a building to the construction queue. Types: Dwelling, Garden, Workshop, FeastHall
ClearForestposition: PositionAssigns an idle builder (or any idle elf) to clear a forest tile at the given coordinates
ScheduleRevel(none)Transitions RevelState from None to Gathering with 5 ticks remaining
Messagetext: StringAdds curator commentary to the UI event log -- no gameplay effect

Command Dispatch

Commands are applied via apply_commands(world, commands, curator). Each command:

  1. Mutates the GameWorld directly (e.g., inserting into policies.workshop_assignments, pushing to policies.build_queue).
  2. Returns a CulturalEvent for the UI log (e.g., RoleAssigned, PriorityShifted, BuildQueued, ReadyForRevel, CuratorMessage).

For QueueBuild, the system first calls find_build_site to locate a suitable position:

  • First choice: nearest meadow tile to the map center that is not occupied or already queued.
  • Fallback: nearest YoungForest tile, which gets cleared first (assigns an idle builder to ClearForest task). The DummyCurator limits this to one clearing per consultation via its cleared_today flag.

The search radius is (min(map_width, map_height) * 0.15).max(5.0) + 6 tiles from center.

The Curator Enum (Runtime Dispatch)

At runtime, the game holds a Curator enum that wraps either variant:

pub enum Curator {
    Dummy(DummyCurator),
    Llm(LlmCurator),
}

On WASM targets (browser build), LlmCurator is a thin stub that delegates to an inner DummyCurator, since the claude CLI is not available in the browser. The UI label shows "rules" for the dummy curator and the model name (e.g., "haiku") for the LLM curator.

State Snapshot Format

The curator never reads GameWorld directly for LLM consumption. Instead, SettlementState::from_world(world) produces a plain-data snapshot that the prompt layer serializes as readable text.

The snapshot includes:

SectionData
HeaderDay, tick, season, day-in-season, year, weather, temperature
ResourcesName, current amount, daily rate -- for Food, Wood, Stone, FineWood
ElvesName, role, task, skills (music/building/gathering), morale, satisfaction, aesthetic label, aesthetic distance from center, friend/rival names, portfolio count, aspirations, fandom, discontented/blocked flags
Aesthetic centerSettlement-wide average on four axes: structure, tradition, emotion, social
CompositionsName, composer, genre, quality tier, mastery/originality/emotional scores, aesthetic position, properties, patron-favorite flag. Capped at 15 most recent
Revel stateCurrent phase (None / Gathering / Performing / Aftermath) plus history of last 5 revels with highlight composition and average score
BuildingsCount by type (Dwelling, Garden, Workshop, FeastHall) plus build queue size
SpiritState label and meter value (0-100)
Current policiesRole assignments and resource priority order

The prompt layer (prompt.rs) adds climate-aware alerts -- winter food warnings below 20, storm shelter alerts, discontented elf warnings, and spirit anger alerts -- before the main state sections.

Interactions

  • Dummy Curator -- the rule-based fallback that handles bootstrap and steady-state decisions.
  • LLM Curator -- the Claude-backed advisor with background threading and structured output.
  • Needs & Mood -- morale values that appear in the state snapshot and inform curator decisions.

Tips

  • The curator only runs at day boundaries by default. If your settlement is in crisis, the LLM curator reacts faster because it also triggers on critical events.
  • Message commands are free -- they have no gameplay cost. The LLM curator uses them to explain its reasoning in the event log.
  • The QueueBuild command does not specify a location. The system automatically finds the best build site near the map center, clearing young forest if no meadow is available.
  • When the LLM curator's background thread dies or claude is not found, it permanently falls back to the DummyCurator for the rest of the session.
  • On WASM (browser), only the dummy curator is available. The LLM curator requires the native TUI build.