Reference Card runtime Feb 2026 v1.0

Urd Schema — Engine Developer Reference Card

Quick reference for developers consuming .urd.json files. Covers the eight schema blocks, property types, containment model, visibility, conditions, effects, dialogue structure, and runtime evaluation order.

referenceengineersschemaruntimeintegrationjson

Key points

  • Eight schema blocks and their JSON structure
  • Property types, containment model, and visibility rules
  • Condition expressions, effects, and runtime evaluation order

Document status: INFORMATIVE Quick reference card for engine integration developers. All rules are derived from the normative Schema Specification and Wyrd Reference Runtime specification. Single canonical copy. February 2026 draft.

URD

Engine Developer Reference Card

Everything you need to consume .urd.json files

urd.dev · February 2026

The .urd.json Contract

A compiled world file is self-contained, deterministic (same source → byte-identical output), versioned, and human-inspectable. It is the single interchange format between authoring and execution.

.urd.md files  →  Compiler  →  .urd.json  →  Your Runtime

Eight Top-Level Blocks

All optional except world. Blocks can appear in any order. Cross-references resolved by compiler.

BlockPurposeRequired
worldMetadata: name, version, start location, entry sequence.Yes
typesEntity type definitions. Property schemas with types, defaults, constraints, visibility.No
entitiesInstances of defined types. Unique IDs, type reference, property overrides.No
locationsSpatial containers with exits and connections.No
rulesNPC behavioural constraints. Trigger → condition → select → effect.No
actionsPlayer-performable interactions. Target, prerequisites, effects.No
sequencesOrdered phase flows. Game show rounds, tutorial steps, ritual stages.No
dialogueFlat map of dialogue sections, choices, jumps, and on_exhausted content.No

The world Block

{
  "world": {
    "name": "monty-hall",
    "version": "1.0",
    "urd": "1",
    "description": "The classic Monty Hall problem",
    "author": "Urd Examples",
    "start": "stage",
    "entry": "game"
  }
}
FieldTypeRequiredNotes
namestringYesLowercase, hyphens allowed.
urdstringYesSchema version. Always "1" for v1. Set by compiler, not author.
versionstringNoAuthor-defined version.
descriptionstringNo
authorstringNo
startlocation refNoPlayer’s starting location.
entrysequence refNoSequence that begins on load.

Property Types

TypeValuesConstraints
booleantrue / false
integerWhole numbersOptional min / max
numberDecimalsOptional min / max
stringText
enumOne of a declared setRequires values array
refEntity IDOptional ref_type for type constraint
listOrdered values or refs

Visibility Model

LevelWho Sees ItUse Case
visibleEveryone (default)Door state, character name
hiddenWorld only. Must be explicitly reveal-ed.Prize behind a door, trap
ownerThe entity itself and the worldNPC private motivations
conditionalVisible when a condition is metClue visible after examining an object

Conditional visibility structure:

{
  "secret_message": {
    "type": "string",
    "default": "The key is under the stone",
    "visibility": {
      "type": "conditional",
      "condition": "magnifying_glass.container == player"
    }
  }
}

Entity Traits

Traits are boolean flags on type definitions that inform spatial capabilities.

TraitMeaning
containerCan hold other entities. Locations have this implicitly.
portableCan be moved into another container (picked up, stored, transferred).
mobileCan move itself between containers (walk between rooms).
interactableCan be the target of player actions. Default: true.

The Containment Model

One spatial primitive. Every entity exists inside exactly one container. Moving, picking up, dropping, and storing are the same operation: changing entity.container.

OperationExpression
Pick up keymove: rusty_key, to: player
Drop key in roommove: rusty_key, to: player.container
Give key to NPCmove: rusty_key, to: guard
Player has key?rusty_key.container == player
Key in same room?rusty_key.container == player.container

The player entity is implicitly a mobile container. No special inventory system needed.

Locations and Exits

{
  "locations": {
    "cell": {
      "description": "A dim stone cell.",
      "contains": ["rusty_key", "guard", "cell_door"],
      "exits": {
        "north": {
          "to": "corridor",
          "condition": "cell_door.locked == false",
          "blocked_message": "The iron door is locked."
        }
      }
    }
  }
}
Exit FieldTypeRequiredNotes
tolocation refYesDestination.
conditionexpressionNoMust be true for traversal.
blocked_messagestringNoShown when condition is false.
effectseffect listNoApplied when exit is used.

Exits are unidirectional. Declare both directions explicitly.

Condition Expressions

String expressions that evaluate to boolean.

entity.property == value       // Equality
entity.property != value       // Inequality
entity.property > value        // Comparison (also <, >=, <=)
entity.container == other      // Containment check
entity.property == true        // Boolean check

Multiple conditions in a list are AND-ed.

OR logic uses the any keyword:

{
  "conditions": {
    "any": [
      "player.reputation > 50",
      "bribe_gold.container == player"
    ]
  }
}

v1 note: any: is part of the v1 JSON schema and writer syntax (? any: block in Schema Markdown). Runtimes must evaluate it.

Effects

EffectJSON StructureDescription
set{ "set": "entity.prop", "to": value }Change a property value.
move{ "move": "entity", "to": "container" }Move entity into a container.
reveal{ "reveal": "entity.prop" }Change hidden → visible.
destroy{ "destroy": "entity" }Remove entity from world.
spawn{ "spawn": { "id": "new_id", "type": "TypeName", "in": "container" } }Create entity at runtime.

There are no separate inventory verbs. move handles pick up, drop, give, loot, and transfer.

Rules

Rules define constrained NPC behaviour: trigger → condition → select → effect.

{
  "rules": {
    "monty_reveals": {
      "actor": "monty",
      "trigger": "phase_is reveal",
      "select": {
        "from": ["door_1", "door_2", "door_3"],
        "as": "target",
        "where": [
          "target.prize != car",
          "target.chosen == false",
          "target.state == closed"
        ]
      },
      "effects": [
        { "set": "target.state", "to": "open" }
      ]
    }
  }
}

Trigger Types

TriggerFires When
phase_is <id>Current sequence reaches the named phase.
action <id>The named action is performed.
enter <location>An entity enters the named location.
state_change <entity.prop>The named property changes value.
alwaysEvery tick (use sparingly).

The select Block

Constrained random choice from a set. If multiple candidates match, runtime chooses randomly. If none match, rule does not fire.

FieldDescription
fromCandidate entity list.
asVariable name for the selected entity (usable in effects).
whereConditions each candidate must satisfy.

Actions

{
  "actions": {
    "pick_up_key": {
      "actor": "player",
      "target": "rusty_key",
      "conditions": ["rusty_key.container == player.container"],
      "effects": [{ "move": "rusty_key", "to": "player" }]
    }
  }
}
FieldTypeRequiredNotes
actorentity refNoDefault: player.
targetentity refNo*Specific entity.
target_typetype refNo*Any entity of this type.
conditionsexpression listNo
effectseffect listYes
descriptionstringNoShown to player.

*Use target (specific entity) or target_type (any matching entity), not both. Neither = self-targeted.

Sequences

Ordered phase flows. Worlds without sequences are freeform.

{
  "sequences": {
    "game": {
      "phases": [
        { "id": "choose", "prompt": "Pick a door.", "action": "choose_door", "advance": "on_action" },
        { "id": "reveal", "auto": true, "rule": "monty_reveals", "advance": "on_rule" },
        { "id": "switch_or_stay", "prompt": "Switch or stay?", "actions": ["switch_door", "stay"], "advance": "on_action" },
        { "id": "resolve", "auto": true, "effects": [{"reveal": "door_1.prize"}], "advance": "end" }
      ]
    }
  }
}

Advance Modes

ModeBehaviour
on_actionAdvance after player completes a listed action.
on_ruleAdvance after the phase’s rule fires.
on_condition <expr>Advance when expression becomes true.
endSequence ends.

Dialogue

The dialogue block is a flat map of sections keyed by world-unique ID.

{
  "dialogue": {
    "tavern/topics": {
      "id": "tavern/topics",
      "prompt": { "speaker": "arina", "text": "What'll it be, stranger?" },
      "choices": [
        {
          "id": "tavern/topics/ask-about-the-harbor",
          "label": "Ask about the harbor",
          "sticky": true,
          "response": { "speaker": "arina", "text": "Quiet today. Too quiet." },
          "effects": [{ "set": "arina.trust", "to": "arina.trust + 5" }],
          "goto": "tavern/topics"
        }
      ],
      "on_exhausted": { "text": "Suit yourself." }
    }
  }
}

Section Fields

FieldTypeRequiredNotes
idstringYesFormat: file_stem/section_name.
promptobjectNo{ speaker, text } — NPC introduction.
descriptionstringNoProse narration before the prompt.
choicesarrayNo
on_exhaustedobjectNoContent when all choices consumed/gated. { text, speaker? }

Choice Fields

FieldTypeRequiredNotes
idstringYesFormat: section_id/slugified-label.
labelstringYesText shown to player.
stickybooleanYestrue = stays; false = consumed after selection.
conditionsexpression listNo
responseobjectNo{ speaker, text }
effectseffect listNo
gotostringNoSection ID to jump to. Omit = stay in section.
choicesarrayNoInline sub-choices (same structure).

Runtime Dialogue Rules

  • One-shot (sticky: false): consumed after selection. Never shown again. Persists across revisits.
  • Sticky (sticky: true): available every visit. Re-evaluate conditions each time.
  • Exhaustion: all choices consumed or gated → fall through to on_exhausted. Never present an empty choice menu.
  • Exhaustion is a runtime predicate, not a stored boolean. No exhausted field in JSON.

Stable ID Derivation

ElementFormatExample
Sectionfile_stem/section_nametavern/topics
Choicesection_id/slugified-labeltavern/topics/ask-about-the-harbor
EntityDeclared @namerusty_key

All IDs are world-unique in compiled JSON.

Runtime Evaluation Order

  1. Load and validate. Parse, resolve types, validate properties.
  2. Instantiate. Create entities with defaults. Place in declared containers.
  3. Evaluate sequences. If entry is declared, start its first phase. Otherwise freeform.
  4. Process actions. Evaluate conditions → apply effects → trigger matching rules.

Wyrd Runtime Characteristics

Wyrd is the reference runtime. Your integration tests against it.

  • Immutable state transitions. Each state change produces a new world state.
  • Event sourcing. Every mutation is a logged event.
  • Seeded randomness. Deterministic replay from a seed.
  • Canonical behaviour. Any ambiguity in the spec is resolved by what Wyrd does.

Schema Coverage by Test Case

PrimitiveTavernMonty HallKey PuzzleInterrogation
world
types
visibility: hidden
visibility: owner
traits: portable
containment as inventory
locations (multi)
exits with conditions
rules with select
actions
sequences
dialogue (sections, choices)
sticky / one-shot
on_exhausted
effects: set
effects: reveal
effects: move
effects: destroy
any: OR conditions

Not yet exercised: conditional visibility, spawn effects. Deferred to future test cases.

v1 Boundaries

FeatureStatus
All eight blocksSupported
any: OR conditionsFully supported. JSON any: block; writer syntax ? any:.
Cross-file section jumpsNot in v1. Use exits for cross-file movement.
Lambda functionsNot in v1. Future extension host.
Conditional visibilitySpecified but not yet test-covered.
Spawn effectsSpecified but not yet test-covered.

Authoritative sources: Schema Specification, Wyrd Reference Runtime specification. This card is a convenience summary.

End of Reference Card