Files
settled-reach/docs/design/content-directory-structure.md
T
jpmschweitzerandClaude Opus 4.6 5fdb7f9c53 docs(design): add content directory structure, update entity attributes, stub Nils Davan
Wave 1 critical blockers for Sprint 3:
- #384: Content directory structure design doc (10 sections + 2 appendices,
  defines canonical IDs, 8 JSON schemas, 3-tier validation pipeline, migration path)
- #374: Update entity-attributes.md (14→16 keys, secret→leverage rename,
  add 4 role-perspective keys, archetype interpretation note)
- #376: Nils Davan off-stage NPC stub (GHOST+HANDLER pattern, lattice messages,
  Triangle 1 role, relationship to Kael)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:45:16 +01:00

29 KiB

Content Directory Structure — The Settled Reach v0.1

Ticket: #384 (blocks #385: directory skeleton, #386: schema definitions) Status: Design specification Authority: This document is the source of truth for the content/ directory layout. The server team implements the directory skeleton (#385) and schema files (#386) against this spec.

Decisions referenced: D-024 (10-axis NPC model), D-027 (vertical slice), D-028 (dialogue architecture), D-032 (monologue partition), D-034 (THE FRIEND), D-035 (tag taxonomy), D-036 (Sova Transit setting), D-049 (YAML format), D-057 (content directory structure)


1. Overview

The content/ directory holds all game content in a structured, validated, mod-compatible layout. It is the canonical runtime format consumed by the Rust/bevy_ecs simulation server. All content files are YAML, validated against JSON Schema definitions at build time and deserialized via serde at load time.

This document defines:

  • The complete directory tree
  • Canonical ID format and naming conventions
  • Schema file inventory and purpose
  • Validation pipeline (3-tier)
  • Migration path from the current wiki (docs/wiki/)

The directory structure is designed so that a district is the atomic content pack unit. Districts can be added, removed, or replaced independently. The structure supports future mod overlay without v0.1 implementation.


2. Top-Level Layout

content/
  content.yaml            # Manifest: district list, content version, load order
  _meta/                  # Infrastructure metadata (underscore prefix = not game content)
    README.md             # Explains _meta and _schema conventions
  _schema/                # JSON Schema validation files
    npc-profile.schema.json
    dialogue-pool.schema.json
    monologue-pool.schema.json
    district.schema.json
    triangle.schema.json
    routine.schema.json
    location.schema.json
    fact-catalog.schema.json
  global/                 # Cross-district content (not district-scoped)
    factions/             # Faction profiles
    technology/           # Technology definitions
    contraband/           # Contraband item profiles
    knowledge/            # Shared FactId definitions, entity attribute enums
    enums/                # Shared enum values (situations, moods, topics, access tiers)
    regions/              # Star system / station metadata
  districts/              # Per-district content packs
    sova-transit/         # v0.1 district (D-036)

Conventions

  • Underscore prefix (_meta/, _schema/): Infrastructure directories. Not game content. The server content loader skips directories starting with _ when scanning for content files.
  • content.yaml: The manifest file. Lists enabled districts, content version, and load order. The server reads this first.
  • global/: Content that applies across all districts. Faction definitions, shared enums, fact catalogs, and region metadata live here.
  • districts/: One subdirectory per district. Each district is a self-contained content pack.

Manifest Format

# content/content.yaml
version: "0.1.0"
districts:
  - id: "sova-transit"
    path: "districts/sova-transit"
    enabled: true

The version field tracks content schema version. The districts list defines load order. Disabled districts are skipped entirely at load time.


3. District Structure

Each district directory is the atomic pack unit. It contains everything the server needs to instantiate that district: NPC profiles, locations, dialogue, monologue, routines, and triangle definitions.

districts/sova-transit/
  district.yaml               # District metadata
  npcs/                        # NPC profile files (one YAML file per NPC)
    kael-davan.yaml
    sera-venn.yaml
    voss.yaml
    lera-sessik.yaml
    torek-lintar.yaml
    devra.yaml
    maret-korr.yaml
    resha.yaml
    naia-tamm.yaml
    renn.yaml
    pell.yaml
    harek.yaml
    drin.yaml
    sess.yaml
    olin.yaml
    sabel.yaml
    tav.yaml
  locations/                   # Location definition files (one per location)
    the-terminal.yaml
    the-last-shift.yaml
    maintenance-corridors.yaml
  templates/                   # Social site template definitions
  triangles/                   # Triangle relationship definitions
    hub-power.yaml
    worried-knowledge.yaml
    bar-tensions.yaml
    worried-partner.yaml
    informant-question.yaml
  dialogue/                    # Tagged dialogue line pools
    the-terminal/              # Subdirectory per location
      dock-worker.yaml         # One file per template role
      shift-supervisor.yaml
      scheduler.yaml
      new-hire.yaml
      courier.yaml
    the-last-shift/
      bar-owner.yaml
      bartender.yaml
      bar-regular.yaml
    maintenance-corridors/
      ring-operative.yaml
  monologue/                   # Tagged monologue line pools (per character)
    smuggler/                  # Hard partition per D-032
      the-terminal.yaml
      the-last-shift.yaml
      maintenance-corridors.yaml
      general.yaml             # Location-independent lines
    detective/
      the-terminal.yaml
      the-last-shift.yaml
      maintenance-corridors.yaml
      general.yaml
  routines/                    # NPC daily routine schedules
    schedules.yaml             # All NPC schedules for this district

District Metadata

# districts/sova-transit/district.yaml
canonical_id: "krenn.sova.transit"
display_name: "Sova Transit District"
system: "krenn"
station: "sova"
district: "transit"
description: >
  A 40-year-old prefab-modular-retrofitted freight logistics hub on Station Sova.
  Three social sites: The Terminal (logistics hub), The Last Shift (bar),
  and maintenance corridors.
locations:
  - "the-terminal"
  - "the-last-shift"
  - "maintenance-corridors"
npc_count: 17

Subdirectory Rationale

Directory Scoped by Rationale
npcs/ One file per NPC NPC profiles are the most frequently edited content. One file per NPC enables parallel authoring and clean diffs.
locations/ One file per location Location metadata (name, tiles, sightlines, ambient) is independent of NPC content.
templates/ One file per social site template Template definitions (roles, triangle slots, NPC capacity) are structural and rarely change after initial authoring.
triangles/ One file per triangle Triangle definitions reference NPCs by canonical ID. Separate files enable independent authoring and review.
dialogue/ Location > role Dialogue lines are authored per template role at a specific location. The location subdirectory groups all roles present at that location. This matches the authoring workflow: write all dialogue for The Terminal, then all dialogue for The Last Shift.
monologue/ Character > location Hard partition by playable character (D-032). Within each character, one file per location plus a general.yaml for location-independent lines.
routines/ Single file per district All NPC schedules in one file enables cross-NPC scheduling validation (no two NPCs assigned to the same tile at the same time).

4. Canonical ID Format

{system}.{station}.{district}.{type}.{slug}

Examples

Canonical ID Resolves to
krenn.sova.transit.npc.kael-davan districts/sova-transit/npcs/kael-davan.yaml
krenn.sova.transit.npc.sera-venn districts/sova-transit/npcs/sera-venn.yaml
krenn.sova.transit.location.the-terminal districts/sova-transit/locations/the-terminal.yaml
krenn.sova.transit.location.the-last-shift districts/sova-transit/locations/the-last-shift.yaml
krenn.sova.transit.triangle.hub-power districts/sova-transit/triangles/hub-power.yaml
krenn.sova.transit.triangle.worried-knowledge districts/sova-transit/triangles/worried-knowledge.yaml

Type Segment Values

Type Description
npc NPC profile
location Location definition
template Social site template
triangle Triangle relationship definition

Rules

  1. Canonical IDs are stable references. Renaming a file does not change its canonical ID. The canonical_id field inside each YAML file is the source of truth. File names are a convenience for human navigation; the loader resolves by canonical_id, not by file path.
  2. Canonical IDs are globally unique. No two content files across any district may share a canonical ID. The build-time validator enforces this.
  3. Slugs use kebab-case. Lowercase, hyphen-separated: kael-davan, the-terminal, hub-power.
  4. Short-form IDs. Within content files, NPC references use the short form npc:{slug} (e.g., npc:kael-davan). Location references use loc:{district}:{slug} (e.g., loc:sova-transit:the-terminal). These short forms are unambiguous within a single district. The full canonical ID is used for cross-district references (future feature).

5. Schema Specifications

All schema files live in content/_schema/. They use JSON Schema draft 2020-12. Each schema file validates one content type.

Schema Inventory

Schema File Validates Key Constraints Decision Reference
npc-profile.schema.json districts/*/npcs/*.yaml 10-axis model (want, secret, relationships, tolerance, routine, information, contentment + personality, tells, skills). Tier-conditional fields: friend_arc only on FRIEND pattern T1 NPCs. Pattern enum (9 values). Motivation enum (6 values). Access tiers. Trust levels. Triangle membership. D-024, D-034
dialogue-pool.schema.json districts/*/dialogue/**/*.yaml Role + location scoped. 6 structural tags (id, text, role, access, trust, situation) + 3 selection tags (topic, mood, tags). Knowledge grants per line. Access is a list (multi-tier eligibility). Situation enum: 13 values. Topic enum: 9 values. Mood enum: 8 values. D-028, D-035
monologue-pool.schema.json districts/*/monologue/**/*.yaml Hard partition by character (smuggler/detective, D-032). Trigger enum: 9 types. Prerequisite object (AND-only logic: facts, entity attributes, relationship state). Priority (0-10). Cooldown (ticks). 160 char max per line (display constraint, D-059). D-032, D-035
district.schema.json districts/*/district.yaml District metadata: canonical_id, display_name, system, station, district slug, description, location list, NPC count. D-036
triangle.schema.json districts/*/triangles/*.yaml Triangle definition: 3 NPC members (by canonical_id short form), roles within the triangle, fork conditions, resolution states. Self-contained forks (no cross-triangle cascade in v0.1). D-024, D-047
routine.schema.json districts/*/routines/*.yaml Schedule entries per NPC: phase (Morning/Afternoon/Evening/Night), location, tile coordinates, activity. Deviation entries: trigger condition, override location/tile/activity. Deviations are load-bearing for FRIEND arc spatial staging. D-034
location.schema.json districts/*/locations/*.yaml Location metadata: canonical_id, display_name, tile bounds, sightline properties, ambient sound reference, social site membership. D-025, D-036
fact-catalog.schema.json global/knowledge/*.yaml Fact definitions: fact_id, description, discoverable_by (character list), progression (confidence levels with description text), abstract flag (whether fact can reach Direct confidence). D-035

Schema Design Principles

  1. Required fields are minimal. Only fields the server needs to instantiate an entity are required. Authoring-only fields (dual_lens, notes) are optional and ignored at load time.
  2. Enum values are defined in schema, mirrored in global/enums/. The JSON Schema files contain the authoritative enum definitions. The global/enums/*.yaml files are the human-readable reference and the source for IDE autocomplete. Both must agree; the build-time validator checks this.
  3. Pattern validation on IDs. Canonical IDs, line IDs, and reference IDs use regex patterns in the schema to catch malformed references at validation time, before the server ever sees them.
  4. Conditional fields. The friend_arc object in npc-profile.schema.json is only present on FRIEND-pattern NPCs. The schema uses JSON Schema if/then for tier-conditional validation where feasible; otherwise, cross-reference validation at build time catches mismatches.

Line ID Formats

Content Type ID Pattern Example
Dialogue {location_slug}_{d}_{###} the-terminal_d_001
Monologue (smuggler) {location_slug}_m_s_{###} the-terminal_m_s_001
Monologue (detective) {location_slug}_m_d_{###} the-terminal_m_d_001
Examine {location_slug}_{e}_{###} the-terminal_e_001

Line IDs are stable. They are never reused, even if a line is deleted. Numbering gaps are expected and acceptable.


6. Global Content Structure

global/
  factions/                    # Faction profiles (cross-district)
    lattice-commission.yaml
    syndics.yaml
    the-ring.yaml
    concord-assembly.yaml
    guardians-of-autonomy.yaml
    veil-institute.yaml
    the-unbound.yaml
  technology/                  # Technology definitions
  contraband/                  # Contraband item profiles
  knowledge/                   # Shared FactId definitions
    contraband.yaml            # Contraband-related facts
    location.yaml              # Location-related facts
    investigation.yaml         # Investigation-related facts
    world.yaml                 # World/setting facts
    relationship.yaml          # Relationship-related facts
    progress.yaml              # Progression-related facts
  enums/                       # Shared enum values
    situations.yaml            # 13 situation values (D-035)
    topics.yaml                # 9 topic values
    moods.yaml                 # 8 mood values
    access-tiers.yaml          # public, insider, authority, peer, hostile
    trust-tiers.yaml           # surface, real, secret
    triggers.yaml              # 9 monologue trigger types
    patterns.yaml              # 9 thematic patterns (System A)
    motivations.yaml           # 6 functional motivations (System B)
  regions/                     # Star system / station metadata
    krenn.yaml                 # Krenn System profile (D-036)

Global Content Rationale

Directory Contents Why Global
factions/ One file per faction. Faction name, description, political stance, NPC membership references. Factions span districts. An NPC in Sova Transit may belong to a faction headquartered elsewhere.
technology/ Technology definitions relevant to gameplay (lattice types, span gate specs). Technology is universal across the setting.
contraband/ Contraband item profiles (unlicensed lattice components, medical-grade replacements, counter-surveillance tech per D-037). Contraband types are not district-specific; the same items may appear in multiple districts.
knowledge/ FactId catalog. Each fact has an ID, description, discoverability, and confidence progression text. Facts are referenced by NPC profiles, dialogue lines, and monologue prerequisites across all districts. The fact catalog is the single source of truth for what can be known.
enums/ Enum value definitions. One file per enum type. Enums are shared vocabulary. Dialogue in any district uses the same 13 situations, 9 topics, and 8 moods.
regions/ Star system and station metadata. Region data provides setting context for districts. Multiple districts may exist on a single station.

Entity Schema (Attribute Keys)

The 16 EntityKnowledge keys (D-055) are defined in:

global/
  knowledge/
    entity-attributes.yaml     # 16 canonical EntityKnowledge keys with value enums

This file defines the attribute key names, their categories (Identity, Spatial, Behavioral, Relational, Role-perspective), allowed value types, and the 4 new role-perspective keys (risk_assessment, loyalty_assessment, position_integrity, moral_weight).


7. File Naming Conventions

General Rules

Rule Convention Example
Extension Always .yaml (never .yml) kael-davan.yaml
Case kebab-case for all filenames the-terminal.yaml, hub-power.yaml
NPC files Named by NPC slug kael-davan.yaml, sera-venn.yaml
Location files Named by location slug the-terminal.yaml, the-last-shift.yaml
Triangle files Named by triangle slug hub-power.yaml, worried-knowledge.yaml
Dialogue files Named by template role dock-worker.yaml, bar-owner.yaml
Monologue files Named by location (inside character subdirectory) smuggler/the-terminal.yaml
General monologue general.yaml for location-independent lines smuggler/general.yaml
Enum files Named by enum type (plural) situations.yaml, moods.yaml
Faction files Named by faction slug lattice-commission.yaml, the-ring.yaml
Fact files Named by fact category contraband.yaml, investigation.yaml

Directory Naming

  • District directories use the district slug: sova-transit/
  • Dialogue subdirectories use the location slug: the-terminal/
  • Monologue subdirectories use the character name: smuggler/, detective/

What NOT to Do

  • Do not use CamelCase or PascalCase in filenames.
  • Do not use underscores in filenames (underscores are reserved for line ID segments).
  • Do not abbreviate names: maintenance-corridors.yaml, not maint-corr.yaml.
  • Do not nest deeper than 3 levels within a district directory.

8. Mod-Compatible Conventions

The directory structure is designed to support future mod overlay, where a mod mirrors the same tree and the loader merges mod content with base content. v0.1 does not implement overlay loading, but the structure is ready for it.

Design Principles

  1. District as atomic pack unit. A mod can add an entirely new district by placing a new directory under districts/. No existing files need modification.
  2. Mirrored tree. A mod that modifies existing content mirrors the exact same directory structure. For example, a mod adding an NPC to Sova Transit would place a file at mod-name/districts/sova-transit/npcs/new-npc.yaml.
  3. Canonical IDs prevent collisions. Because canonical IDs include the system/station/district prefix, mods in different districts cannot accidentally collide. Mods in the same district use a mod-specific prefix convention (future spec).
  4. Global content extension. A mod can add new factions, facts, or enum values by placing files in mod-name/global/. The overlay loader (future) merges these with base global content.

v0.1 Scope

  • The directory structure is mod-compatible by design.
  • No overlay loader is implemented in v0.1.
  • No mod tooling, mod manifest format, or mod loading order is defined in v0.1.
  • These are future tickets. The only v0.1 requirement is that the base content structure does not preclude mod overlay.

9. Validation Pipeline

Content validation operates at three tiers. Each tier catches different classes of errors. All three must pass for content to be considered valid.

Tier 1: Authoring-Time (IDE)

Tool: YAML Language Server + JSON Schema association What it catches: Syntax errors, missing required fields, wrong field types, invalid enum values.

Configuration: each YAML content file includes a $schema comment or the IDE is configured to associate _schema/*.schema.json files with the corresponding content directories.

# Example: NPC profile with schema association
# yaml-language-server: $schema=../../_schema/npc-profile.schema.json
canonical_id: "npc:kael-davan"
display_name: "Kael Davan"
# ...

This tier is optional (not all authors use IDE schema validation) but strongly recommended. It provides instant feedback during authoring.

Tier 2: Build-Time (make validate-content)

Tool: tooling/content-tools validate content/ (Rust CLI) What it catches: Everything Tier 1 catches, plus cross-reference errors.

Build-time validation runs two passes:

Pass 1 — JSON Schema validation:

  • Every YAML file in content/ is validated against its corresponding _schema/*.schema.json file.
  • File-to-schema mapping is determined by directory location (all files in districts/*/npcs/ validate against npc-profile.schema.json).
  • All errors are collected and reported at once (no fail-on-first).

Pass 2 — Cross-reference validation:

  • All canonical_id references resolve to existing files.
  • All FactId references in prerequisites resolve to defined facts in global/knowledge/.
  • All NPC relationship targets (npc:{slug}) resolve to existing NPC profiles.
  • All location references (loc:{district}:{slug}) resolve to existing location files.
  • All triangle member references resolve to existing NPC profiles.
  • No duplicate canonical_id values across all files.
  • Enum values in content files match definitions in global/enums/.
  • Monologue character partitions are correct (no smuggler lines in detective files, no detective lines in smuggler files).
  • Routine schedule locations resolve to existing location files.

Exit code: 0 if all checks pass, non-zero if any errors. CI gate: content changes must pass make validate-content.

Tier 3: Load-Time (Server Startup)

Tool: Rust serde_yaml deserialization + semantic validation in server/src/content/ What it catches: Type mismatches between YAML and Rust structs (schema drift), semantic errors that require runtime context.

Load-time validation runs in sequence:

  1. Deserialization: serde_yaml::from_str() deserializes each YAML file into the corresponding Rust struct. Any type mismatch, missing required field, or unrecognized enum value causes an immediate load failure. This catches schema drift between the JSON Schema definitions and the Rust struct definitions.
  2. StableId assignment: Deterministic integer IDs are assigned from sorted canonical IDs. This produces repeatable entity IDs across loads.
  3. Relationship wiring: Canonical ID references (npc:{slug}) are resolved to StableIds. Unresolvable references cause load failure.
  4. FriendArc bonding: FRIEND-pattern NPC profiles are linked to their bonded playable character via StableId.
  5. Schedule validation: Routine entries are checked for location/tile validity.

Failure mode: The server fails fast on any load-time error. No partial loads. All content must be valid or the server does not start. This is intentional: partial content loads produce subtle, hard-to-debug runtime errors.


10. Migration Path

Current State

Game content currently lives in docs/wiki/, organized as human-readable Markdown files:

docs/wiki/
  npcs/           # NPC profile pages (Markdown)
  factions/       # Faction descriptions
  knowledge/      # FactId catalog, entity attributes
  locations/      # Location descriptions
  contraband/     # Contraband profiles
  technology/     # Technology descriptions
  world/          # World-building (Krenn System, Sova Station)
  authoring/      # Authoring guides and style references
  index.md        # Wiki index

Migration Strategy

The wiki (docs/wiki/) remains the authoring source during v0.1. Authors write and edit in the wiki. The content/ directory is the runtime format — what the server loads.

The conversion from wiki Markdown to runtime YAML is a manual process during v0.1, tracked as ticket #398 (future). The process:

  1. Author writes/edits NPC profile in docs/wiki/npcs/kael-davan.md.
  2. Author (or tooling) converts the profile to content/districts/sova-transit/npcs/kael-davan.yaml, conforming to _schema/npc-profile.schema.json.
  3. make validate-content confirms the YAML is valid.
  4. Server loads from content/.

Mapping Table

Wiki Source Content Target Notes
docs/wiki/npcs/*.md content/districts/sova-transit/npcs/*.yaml One-to-one mapping. Wiki profile is the human-readable source; YAML is the machine-readable runtime format.
docs/wiki/factions/*.md content/global/factions/*.yaml Faction profiles converted to structured YAML.
docs/wiki/knowledge/fact-catalog.md content/global/knowledge/*.yaml Single Markdown catalog splits into per-category YAML files.
docs/wiki/knowledge/entity-attributes.md content/global/knowledge/entity-attributes.yaml EntityKnowledge key definitions.
docs/wiki/contraband/*.md content/global/contraband/*.yaml Contraband item profiles.
docs/wiki/locations/*.md content/districts/sova-transit/locations/*.yaml Location metadata extracted from descriptions.
docs/wiki/world/*.md content/global/regions/*.yaml System/station metadata.
(new content) content/districts/sova-transit/dialogue/**/*.yaml Dialogue pools are new content authored directly in YAML. No wiki source.
(new content) content/districts/sova-transit/monologue/**/*.yaml Monologue pools are new content authored directly in YAML. No wiki source.
(new content) content/districts/sova-transit/routines/*.yaml Routine schedules are new content authored directly in YAML. No wiki source.
(new content) content/districts/sova-transit/triangles/*.yaml Triangle definitions are new content authored directly in YAML. No wiki source.

What the Wiki Is NOT

The wiki is not deprecated. It remains the primary authoring and review surface for narrative content. Authors should not be expected to write raw YAML for narrative text. The conversion to YAML is a production step, not an authoring step.

Dialogue, monologue, routines, and triangles are exceptions: these content types are authored directly in YAML because their structure is inherently machine-readable (tagged line pools, schedule entries, relationship definitions). The schemas provide IDE autocomplete for these files.


Appendix A: Complete Directory Tree (v0.1)

content/
  content.yaml
  _meta/
    README.md
  _schema/
    npc-profile.schema.json
    dialogue-pool.schema.json
    monologue-pool.schema.json
    district.schema.json
    triangle.schema.json
    routine.schema.json
    location.schema.json
    fact-catalog.schema.json
  global/
    factions/
      lattice-commission.yaml
      syndics.yaml
      the-ring.yaml
      concord-assembly.yaml
      guardians-of-autonomy.yaml
      veil-institute.yaml
      the-unbound.yaml
    technology/
    contraband/
    knowledge/
      contraband.yaml
      location.yaml
      investigation.yaml
      world.yaml
      relationship.yaml
      progress.yaml
      entity-attributes.yaml
    enums/
      situations.yaml
      topics.yaml
      moods.yaml
      access-tiers.yaml
      trust-tiers.yaml
      triggers.yaml
      patterns.yaml
      motivations.yaml
    regions/
      krenn.yaml
  districts/
    sova-transit/
      district.yaml
      npcs/
        kael-davan.yaml
        sera-venn.yaml
        voss.yaml
        lera-sessik.yaml
        torek-lintar.yaml
        devra.yaml
        maret-korr.yaml
        resha.yaml
        naia-tamm.yaml
        renn.yaml
        pell.yaml
        harek.yaml
        drin.yaml
        sess.yaml
        olin.yaml
        sabel.yaml
        tav.yaml
      locations/
        the-terminal.yaml
        the-last-shift.yaml
        maintenance-corridors.yaml
      templates/
      triangles/
        hub-power.yaml
        worried-knowledge.yaml
        bar-tensions.yaml
        worried-partner.yaml
        informant-question.yaml
      dialogue/
        the-terminal/
          dock-worker.yaml
          shift-supervisor.yaml
          scheduler.yaml
          new-hire.yaml
          courier.yaml
        the-last-shift/
          bar-owner.yaml
          bartender.yaml
          bar-regular.yaml
        maintenance-corridors/
          ring-operative.yaml
      monologue/
        smuggler/
          the-terminal.yaml
          the-last-shift.yaml
          maintenance-corridors.yaml
          general.yaml
        detective/
          the-terminal.yaml
          the-last-shift.yaml
          maintenance-corridors.yaml
          general.yaml
      routines/
        schedules.yaml

Appendix B: Enum Value Reference (v0.1)

For quick reference during authoring. Authoritative source: content/global/enums/*.yaml.

Situations (13): arrival, shift_start, shift_end, shift_transition, bar_evening, night_shift, investigation, confrontation, social, alone, emergency, routine, observation

Topics (9): colleague, routine, cargo, money, trust, danger, institution, personal, investigation

Moods (8): fond, comfortable, worried, suspicious, analytical, conflicted, concerned, relieved

Access Tiers (5): public, insider, authority, peer, hostile

Trust Tiers (3): surface, real, secret

Monologue Triggers (9): enter_location, observe_npc, hear_sound, observe_anomaly, post_conversation, discover_evidence, witness_interaction, time_idle, return_visit

NPC Patterns (9): FRIEND, MIRROR, ANCHOR, GHOST, CATALYST, THRESHOLD, REMNANT, SYSTEM, NOBODY

NPC Motivations (6): HANDLER, WITNESS, TURNCOAT, CIVILIAN, OPERATOR, SKEPTIC

NPC Tiers (3): 1 (production-level), 2 (full template), 3 (background)


Ticket #384 — Content directory structure design. Blocks #385 (directory skeleton) and #386 (schema definitions).