Manifesto

OpenXP Experience Format Manifesto: Designer intent, declared

This manifesto sets out the principles that govern the design decisions for the OpenXP experience format: designer intent, declared. Every feature, keyword, rule, and constraint in the format traces to one or more of these principles.

This manifesto is the canonical single source of truth. Every rule, schema, fixture, test, tool, and implementation exists in service of these principles. Where any of them disagrees with a principle, the principle wins and the disagreeing artefact contains a defect. This holds for artefacts that already exist, not only for features being proposed.

It follows that an implementation's behaviour is never evidence of what a principle means. Where code and principle disagree, the code is wrong. Recording observed behaviour into the specification to settle such a disagreement converts a defect into the definition, and is precisely the outcome this precedence exists to prevent.

Where the manifesto is silent on a question, admits two readings that imply different behaviour, or contradicts itself, the question is escalated to the platform owner and settled before the work proceeds — never resolved by inference from the rules or the code. A claim that no principle applies must name the principles considered and why each does not; silence is a finding, not a default. The precedence hierarchy and the change obligations are Principle P507 (Manifesto Supremacy); R905 (Manifesto Change Review) binds their enforcement. The manifesto delegates enforcement downward, never meaning.

The principles are organised and prioritised into themed sections. When two principles appear to conflict, earlier sections take precedence (Safety over Composability, Privacy over Governance), but true conflicts should be resolved by design, not by override. Principles within a section are presented in a logical sequence but all carry equal weight unless explicitly stated.

Human-Centred Design

Experience Files Declare Intent

Public framing

OpenXP puts the designer in charge. The designer's creative vision and intent is written into a single “experience” file as structured data, not filed away as a brief no one reads. Every line of an OpenXP experience file is a commitment to what the experience will be — what the participant inhabits, what touchpoints exist, why specific actions fire. The runtime command (# openxp run my-experience.xp --venue my-venue.xpvenue) serves that commitment; sensors, agents, and environmental variation cannot override it. This is more than a language for running tonight's show: it is a format for the future of experiences, and intent is its centre. The vision is written once, at authoring, in the designer's own words, and travels with the experience to everyone and everything that must understand it — a producer, a supplier, an art director, an operator, an actor, an agent, an archive, and tools not yet conceived — none of whom need to run it. The runtime executes the instructions written beneath that intent and never interprets the intent itself. A camera reading a room, an agent proposing a cue, an operator stepping in at the desk: all of them serve the declaration. None of them redefine it.

Technical framing

The format is a declarative language. Every primitive — every field, every block, every annotation — is a declaration of what the designer commits the experience to be. There are no observation primitives, no descriptive primitives, no inferred-from-runtime primitives in the format. Declaration is the only mode the language operates in.

This is the foundational principle. Every other principle, every primitive shape, every rule and verifier, every export to runtime is in service of this commitment.

Three levels of intent declaration

The format declares intent at three levels, each more specific than the last:

  1. Architectural Primitives declare the shape of the experience — what kind it is and what it commits to as a state of being: realm, domain, modality, synchronicity, senses, accessibility, processing, authority. These are commitments, not constraints: the experience IS this shape from declaration onward; nothing toggles them at runtime. Together they answer "what kind of experience is this, what senses does it engage, who is it for, and how does it handle data?"
  2. Structural primitives declare the capability and boundary the designer commits to expose — what the experience can do and within what limits: touchpoints (the perceptual, output, sensor, and control surfaces — including all perception.X subtypes per Principle P002), journey and state (the state-machine spine), actors and agents (live human delivery + AI participants), policies (the active operational rules per Principles P103–P105), ensembles (bounded participant groupings), environments and zones (spatial regions), plus associated pipeline primitives (capture, deliver) and supporting structures (timelines, properties, safety, assets, schema). Each is exhaustively defined in the format specification (xp-spec-X.X.json); the list here is representative of the structural-intent surface, not exhaustive.
  3. Operational annotations declare the human purpose behind specific actions and transitions: the intent: field is mandatory at experience-body and journey-body, and inherits down the scope tree (per Principle P601). Declared intent sits beside the mechanical operations it explains and gives each its why: the operations say what happens, the intent says why that moment in the experience exists, and the runtime executes the one and never interprets the other (P110).

All three levels carry equal weight as declarations. They are not "primitives plus annotations" — they are intent declared at three different scales of the experience.

Commitment vs Constraint. Architectural primitives are commitments — they describe what the experience IS, durably and unconditionally. processing declares the experience's privacy posture; accessibility declares the experience's commitment to participant needs; realm declares where it lives. These are inviolable by design: the format has no construct that changes them mid-execution, and a conforming runtime MUST NOT alter them at runtime. Structural primitives include both capability surfaces (touchpoints, journeys, ensembles — things the experience HAS) and active rules (policies — things the experience ENFORCES). A designer who treats processing as a togglable rule rather than a foundational commitment has misread the level.

Intent is read at every stage, interpreted by many, and executed by none. Three verbs, each with one meaning. To read intent is to receive it as data: the resolved chain from the experience root to the current block, available to any consumer at any time (R302). To interpret intent is to derive meaning from its natural language, to understand the experience or to propose for it: the author at the desk; an authoring tool that proposes instructions the author approves; a supplier binding a venue; a producer reading the show book; an agency or art director judging fidelity; an accessibility reviewer; an operator at the desk; an actor on the floor; an archive; tools not yet conceived; and, during the show itself, two parts of the runtime: the deliberative and compositional tiers, which the next paragraph names. To execute is what the runtime does with definitions, and execution never reads intent: no guard, transition, policy or dispatch is selected by the words of an intent (P110). One sentence holds the three apart: the output of interpretation never executes as itself; it becomes executable only as instructions in defined words, admitted by a person at authoring (P508) or by policy during the show (P106). Instructions without intent are a cue list; intent without instructions is a brief; an experience file carries both, separated by position, so that everything that must understand the experience can, and only the runtime executes it.

Intent reaches a live experience through the deliberative and compositional tiers, and never through the reactive one. Everything else that interprets intent does so before the show or after it. During the show, two parts of the runtime interpret it, both through a backend the file declares as an agent's model — a language model, or a decision service that holds authority over facts the file does not model: a story, a game, a schedule — reached through a connector that carries no logic of its own. The deliberative agent tier (P106) decides what happens next: at each moment it is given the resolved intent chain for the current block, the readings the room is emitting (P003), the state the journey is in and the transitions declared from it, and from those it proposes — a defined action drawn from the vocabulary the file already declares, with its arguments, or a choice among the paths the file already contains, delivered as an event with a typed payload — never a new word, never a transition of its own making, never an edit to the file. The compositional tier decides what is made: over minutes it sequences steps — a decision, a generation, a selection — with the same intent chain passed into each, and what it proposes is content and structure the file already has a place for: an asset for a declared slot, a scene for a declared touchpoint, a set chosen from declared sets. The reactive tier never interprets: it evaluates a rule over defined words in microseconds, with no model behind it, and where a fast interpretation is wanted the route is a deliberative agent with a short deadline whose fallback is a reactive rule, not a reactive rule that reads words. Every proposal from an interpreting tier enters the same gate: the policies admit or refuse it at their tiers (P103–P105), the operator and the actor outrank it (P106, P005), a proposal naming a word the file cannot resolve is refused (R424), and its declared fallback runs when it is silent past its deadline (R413, R414). This is how intent influences a live experience without ever defining the action: the designer wrote why the moment exists and which paths it may take; the tiers read that why against what the room is doing and offer a what; the policies, written by the same designer, decide whether the what is allowed. It is the entry point the format provides for in-the-moment intelligence, and it puts nothing at risk that the file did not already permit, because a tier cannot do anything the file could not have declared and a policy has not allowed.

experience.xp
1 
2experience "Multi-Sensory Gallery Experience" {
3 intent: "A guided gallery walk that meets every sense without overwhelming any"
4 // Architectural — the shape of the experience
5 realm: physical // physical venue delivery
6 domain: cultural // experience industry context (R231)
7 modality: [guided, ambient] // composable delivery modes (R232)
8 synchronicity: synchronous // timeline-bound execution (R233)
9 senses: [sight, sound] // sensory composition (P601 inheritance)
10 
11 accessibility { // commitment to participant needs (R225-R230)
12 navigational { wheelchair: true, step.free: true }
13 perceptual { language.sign: [it, en], warning.photosensitive: false }
14 }
15 
16 processing { // privacy commitment (P201, R501-R508)
17 mode: transient
18 purpose: "adapt the experience to the guest in the moment"
19 lawful.basis: consent
20 classification {
21 confidentiality: internal
22 integrity: medium
23 availability: low
24 }
25 }
26 
27 // Structural — the capabilities and boundaries
28 touchpoints {
29 farewell_moment: perception.calm { // perception subtype (P002)
30 intent: "Give the guest a sense of completion and gratitude" // operational intent
31 source: authored
32 }
33 }
34 
35 journey "main" {
36 intent: "Hold the guest in the active scene until the session closes gracefully"
37 initial: active
38 terminal: [farewell]
39 state active {
40 on.enter {
41 do: timer.start(name: "session", seconds: 3600) // the session is a named timer (R416)
42 }
43 on timer.session.expired -> farewell {
44 intent: "Transition gracefully rather than abruptly ending" // operational intent
45 do: output.scene(name: "farewell")
46 }
47 }
48 state farewell { }
49 }
50}

Declarations describe actual instances, not conceptual possibility

Every experience file declaration refers to the actual thing the experience commits to. A touchpoint's realm declares where that touchpoint instance actually exists; not where similar touchpoints could exist, not where a participant might perceive it as existing, not where a future implementation might place it. A modality declaration commits to which sense channels actually carry the experience; not which channels could conceivably carry it. A domain declaration commits to what the experience actually IS; not which conceptual categories it could be classified under.

The distinction matters because the format is executing an experience, not describing a possibility space. An output.lighting instance connected to DMX lighting hardware exists in the physical realm because the rendering happens in physical space. The same touchpoint type backed by AR rendering of light exists in the augmented realm because the rendering happens in augmented space. These are different instances of the same touchpoint type, with different realm declarations. Neither is a "conceptual" lighting touchpoint; both are actual lighting instances, differing only in where they actually render.

This is what eliminates ambiguity from the format. Without the actual-not-conceptual rule, every declaration becomes negotiable: "could a participant perceive this lighting as part of an AR experience? maybe? so should it be declared augmented?" — and the declaration carries no commitment. With the rule, the declaration is unambiguous: where does the actual lighting render? That is its realm. Whether a participant perceives it as part of an AR scene or not is a separate question, answered elsewhere in the experience definition (typically by the journey's state realm, not by the touchpoint's realm).

Deliberate limits

  • P001.commitment-switched
    • Limit: switching on or off, or changing, while the show runs, a promise a scope declares: its senses, its realm, its modality, its accessibility promise or its processing. The change is made by an action, a rule or an AI in place of the part of the show that declares the promise. [an action, policy or agent that changes a declared promise]
    • Not this: a device stopping or clearing its output, by the stop or clear command its connector declares, which changes no promise; the journey moving into a part of the show that declares a different promise of its own.
    • Instead: in-file: each promise is declared per scope and inherited (P601). The journey moves between scopes, and a scope that captures after consent carries its own processing { } block with a privacy-tier policy that checks the consent (P103, P204).
    • Attempted in: action name; action argument; policy; agent declaration.
    • Message to the author: "What a part of the show promises (the senses it reaches, its realm, its mode of engagement, its access for guests and how it treats what it captures) is not switched on and off during the night. Where a promise differs between parts of the show, each part states its own, and the show moves between them."

Rationale

A specification that conflates declaration with observation is a specification where designer commitment can be silently overridden — by runtime conditions, by sensor input, by agent inference, by environmental variation. The format exists to make designer commitment first-class and durable across all of these.

The format captures designer commitment. The runtime, the agents, the simulators, the actors, the sensors, and the accessibility systems serve that commitment — they make immersion felt, lighting warm, agent reasoning coherent, accessibility real. Participant experience is the whole point of the work.

Runtime input is integral to this. A camera detecting boredom in an experience whose intent is "excitement" does not redefine the intent — it informs the runtime that reality has diverged from the designer's commitment, so the runtime, the actors, and the agents can act to restore it. Sensors, AI agents, and human actors form a closed loop that tracks the declared intent as its set-point. Inputs drive and measure the objective; declared intent is the objective.

The principle is one of authority, not isolation. Observation flows up; declarations stay constant; runtime closes the gap.

Operational intent annotations are not comments; they are functional metadata. The same is true at the structural and architectural levels — fields are not configuration values, they are design commitments. When an AI agent needs to adapt an experience for a different venue, audience, or mood, it consults the declarations at every level: what kind of experience is this (architectural), what capabilities does it expose (structural), what human purpose drives this specific action (operational). The agent serves the declarations; it does not overrule them. The chain is structured, per scope and inherited, rather than a comment, so that a reader who was not in the room and a tool that does not yet exist can take it whole and build on it; that is what makes the format one for the future of experiences rather than a cue list for tonight.

Intent Compounds Through Inheritance. Intent declarations inherit down the lexical scope tree from experience to journey to state to transition. At every level, the resolved intent is the chain of declared intents from experience root to the current block. The deliberative agent (and any consumer of the format) MUST receive the full resolved chain — not just the local declaration — to construct an accurate mental model of why this block exists. Override semantics are REPLACE-on-override (per Principle P601); the parent chain remains traversable. Intent is mandatory at experience-body (the experience's soul) and journey-body (the journey's spine); optional at lower scopes where inheritance applies. Where omitted, the block inherits the nearest enclosing intent.

Experiences Serve Perception

Public framing

OpenXP gives designers a vocabulary for what people actually feel. Six core perceptions — warmth, energy, tension, calm, wonder, and presence — are the design surface the format exposes. A designer working in OpenXP doesn't begin by wiring DMX channels or scripting cue lists; they begin by naming the perception the moment is built to produce. Warmth is the texture of welcome. Energy is the pulse of a room alive. Tension is the held breath before resolution. Calm is where thoughts settle. Wonder is the moment everything shifts. Presence is the feeling of being truly here, now. The runtime, the lighting rig, the spatial audio, the actor's read of the room — all of them serve those declarations. The compilation from "design for wonder" to "DMX universe 1, channels 1–24, warm amber at 70%" lives below the line; the designer stays above it.

P002 is the direct extension of P001 at the level of perception. P001 says every primitive in the format is a declaration of intent; P002 says that at the human level, intent is expressed in the language of feeling and perception. This is the language Shakespeare wrote into his stage directions, the language ritual, ceremony, and theatre have carried for thousands of years, the through-line that every memorable experience — from a play, to a museum gallery, to a theme park attraction, to a brand activation — is built on. The format is the first specification to make that language declarative, structured, and portable. It encodes a long inheritance of creative practice into a form a runtime can execute, a venue can carry forward, and another designer can read.

Technical framing

The fundamental unit of design is human perception — what someone sees, hears, feels, or senses — not a DMX channel, MIDI note, or API call. You describe what people experience, and what machines execute. The mechanical substrate (hardware protocols, sensor readings, actuator commands) exists to produce perceptions. The format provides a human layer above this mechanical layer: designers author in terms of perceptions and intents. The runtime lowers a perception that binds a source to that source, and a scenography axis to its actuator, deterministically (R301, R306); it never derives an operation from the name of a feeling. The rest of the way from "warmth" to a warm amber is walked by the people who read the declaration — the lighting designer, the actor — and by the venue binding, which is where a scene name becomes a fixture.

P002 stands on its own terms. The declaration is valuable whether or not any sensor will later corroborate it. An actor reading the format knows what to deliver. A lighting designer knows what mood to compose. A producer knows the arc the audience will travel. The measurement of an experience is not a sensor reading; it is the way one guest describes the show to another, the photograph that gets shared, the memory that returns years later. The network that carries an experience is human connection, not wires.

experience.xp
1 
2touchpoints {
3 // Describes what the guest perceives
4 welcome_glow: perception.warmth {
5 intent: "Create a sense of arrival and belonging"
6 realm: physical
7 }
8}
9 
10// Bound at the venue and composed by its lighting designer, this becomes:
11// → DMX universe 1, channels 1-24, warm amber at 70%
12// → LED strip zone "entrance", pattern "pulse", colour #F59E0B
13// The runtime executes that binding; it does not derive it from the word.

The six core perceptions are the design vocabulary. Each names something the designer commits the experience to produce, expressed in terms a human reader recognises. They are authored intent, not telemetry. The runtime — actors, agents, and mechanical outputs together — works to deliver them.

Warmth

The emotional tone of welcome. How a space says hello before anyone speaks.

experience.xp
1 
2// Perception as authored intent
3perception.targets: { warmth: { min: 0.6, ramp: "gentle" } }

Energy

Collective vitality. The pulse of a room full of people alive to what's happening.

experience.xp
1 
2// Shape energy upward
3perception.targets: { energy: { max: 0.95, ramp: "burst" } }

Tension

The held breath of a moment that hasn't resolved. The shape of suspense.

experience.xp
1 
2// Hold a suspense window
3perception.targets: { tension: { min: 0.5, max: 0.8 } }

Calm

The peaceful quality of a contemplative space. Where thoughts settle.

experience.xp
1 
2// Design for sustained calm
3perception.targets: { calm: { min: 0.7, ramp: "sustained" } }

Wonder

Awe and discovery. The moment everything shifts.

experience.xp
1 
2// Design wonder as a peak
3perception.targets: { wonder: { min: 0.8, ramp: "burst" } }

Presence

Spatial awareness. The feeling of being truly here, now.

experience.xp
1 
2// Design presence upward
3perception.targets: { presence: { min: 0.6, ramp: "gentle" } }

Rationale

Donald Hoffman's Interface Theory of Perception demonstrates that our perceptions are not faithful representations of objective reality — they are adaptive interfaces shaped by evolution for fitness, not truth. A red warning light is not "really" red; redness is an interface our visual system constructs. The format takes this insight seriously: we design experiences at the interface level (perceptions, feelings, intents) because that is the level at which humans actually operate. The mechanical substrate is the hidden reality behind the interface. Hoffman's work informs this hierarchy but the format uses its own terminology — perception, intent, senses — rather than claiming to implement any other formal framework.

Feelings Are First-Class

Technical framing

Where P002 establishes the design language of perception and feeling, P003 establishes that the same affective qualities can also enter the runtime as signals, when the technology is available to support it. Emotions, comfort levels, excitement, and other affective states are not side effects — they are first-class inputs to the state machine, as legitimate as an NFC tap or a button press. The format treats feelings as typed data with units, ranges, and sensor mappings.

P003 augments P002; it does not validate it. An experience file expressed in P002 is complete on its own — an actor-led piece with no sensors is a fully valid experience, and many of the most memorable experiences ever staged were exactly that. What P003 adds is responsiveness in time: when a runtime can read affect, it can support the declared intent more attentively. Cues can adjust to the room. Actors can prompt changes, and be prompted. Deliberative agents can respond to intended perceptions, and reach for the next palette.

Mechanically, P003 inherits from P002. The same perception.warmth declaration that authors warmth as intent in P002 also exposes it as a channel the runtime can read when a source is bound. The declaration is not duplicated — same name, same range, now optionally readable. P003 does not introduce a parallel vocabulary; it activates the one P002 already established.

A biometric reading is a perception. A crowd energy level is a perception. A dwell time indicating boredom is a perception. These are not metadata — they are first-class inputs to the state machine. A sensor or an actor can trigger transitions on wonder, shape scenes with calm, and adapt entire journeys to the emotional arc of the room.

experience.xp
1 
2// Perception as runtime signal: warmth measured from a thermal/colour proxy
3on warmth.change -> deepen_welcome {
4 guard: warmth.reading < 0.4
5 do: lights.cue("amber_embrace")
6}
7 
8// Perception sourced from a biometric sensor and aggregated
9touchpoints {
10 crowd_mood: perception.energy {
11 source: sensor.biometric
12 range: [0.0, 1.0]
13 source.window: 30s
14 }
15}
16 
17journey "adaptive_show" {
18 terminal: none
19 state performing {
20 on crowd_mood.reading -> intensify {
21 guard: crowd_mood.value > 0.8
22 do: output.scene(name: "high_energy")
23 }
24 on crowd_mood.reading -> calm {
25 guard: crowd_mood.value < 0.3
26 do: output.scene(name: "gentle")
27 }
28 }
29}

The source of a perception reading is not fixed. An actor can declare a reading through an actor.* touchpoint (per Principle P005). A reactive agent can derive a value from a window of lower-level signals. A camera can yield a crowd-energy aggregate. Whatever the source, the reading enters the state machine through the same first-class channel.

P002 and P003 are separate principles because both halves stand alone in different ways. A designer can author a complete P002-compliant experience without any P003 measurement: actors and static cues deliver the declared targets, and the experience holds. A runtime can stream rich P003 readings without any P002 declarations, but those readings would be telemetry without creative meaning — numbers without an intent to serve. Together they form the cycle of authored intent and responsive delivery: P002 declares, the runtime executes, P003 listens, the runtime adapts, the declaration holds. Both halves are real on their own terms; together they close the cycle.

Rationale

Every experience produces emotional responses. P003 makes them legible to the runtime as structured signals — typed, ranged, sourced — rather than leaving them implicit in the room. When the runtime can read affect, it can support the designer's intent more responsively. The transmission of the experience itself is still human: guest to friend, photo to feed, memory across time. P003 is how the runtime listens in real time, in service of the intent declared in P002.

The Participant Completes the Experience

Public framing

An OpenXP experience is deliberately incomplete. The format file is not a script the participant performs; it is a set of conditions the participant inhabits and finishes in their own way. Shakespeare's plays endure across four centuries because they admit the audience as the final author of meaning, and remain different on every staging. Keats called this Negative Capability — the capacity to hold uncertainty without collapsing it into a fixed reading. OpenXP makes this architectural rather than incidental. Designers commit to conditions — moments, perceptions, materials, cues, actor judgment, agent attention — and trust the human in the room to inhabit them. An experience that tries to control how participants feel is brittle, because human response refuses control. An experience that encodes conditions and trusts the participant to complete them holds, because it admits human variation as the architecture rather than as the edge case.

Technical framing

The participant is the only first-class entity in an experience whose presence cannot be declared and whose behaviour cannot be specified. They arrive, inhabit, interpret, and depart, bringing with them their own perception, history, attention, and meaning. P001 declares the designer's intent. P002 expresses that intent in the language of perception. P003 lets the runtime listen for affective signals when the technology supports it. P004 names the asymmetry the other three depend on: the experience file encodes the conditions for the experience; the participant completes it.

This is not a limitation of the language. It is the architecture. An experience that tries to control participant response is brittle, because human response cannot be controlled. An experience that encodes conditions — moments, perceptions, materials, cues, actor judgment, agent attention — and trusts the participant to inhabit them is robust, because it admits human variation as foundational rather than as edge case. Shakespeare's plays endure across four centuries and every culture they have travelled to because they are deliberately incomplete; the audience completes them, and completes them differently every time. Keats called this quality Negative Capability — the capacity to be in uncertainties, mysteries, and doubts, without irritable reaching after fact and reason. The format is the first executable specification that names this quality as a design principle.

P004 makes the other three principles cohere by clarifying what they each claim and what they do not.

P001's declarations describe what the experience commits to be, not what each participant will feel. A realm: physical declaration commits the experience to physical delivery; it does not commit the participant to a physical experience of presence — some participants may feel dislocated, transported, or absent. The declaration is real; the response is not predicted.

P002's design vocabulary is for authoring conditions, not for engineering response. A perception.warmth { intent: "welcome" } declaration commits the experience to producing the conditions of welcome; whether a particular participant feels welcome on a particular day is the participant's completion, not the system's verification.

P003's measurement, where present, supports responsiveness, never validation. A camera reading low crowd energy does not mean the design failed; it means the runtime now has the information to adjust in service of the declared intent. Absence of measurement does not mean the experience failed either; it means the participant's completion is happening privately, as it does in every actor-led piece staged for millennia.

P005's actors are the principal vehicles of participant completion when sensors and agents are absent — an actor reading the room is the runtime's oldest measurement channel, predating every electronic sensor by thousands of years.

experience.xp
1 
2touchpoints {
3 // Authored, no measurement intended — common in theatre, ceremony, contemplative spaces
4 third_act_wonder: perception.wonder {
5 intent: "Guests feel the scale of what they have witnessed"
6 range: [0.0, 1.0]
7 source: authored
8 }
9 
10 // Measured, source bound — common in adaptive light/sound, biometric-driven work
11 crowd_mood: perception.energy {
12 intent: "Adapt scene pacing to room energy"
13 range: [0.0, 1.0]
14 source: sensor.biometric
15 source.window: 30s
16 }
17 
18 // Considered, not yet bound — common in multi-venue deployment
19 arrival_warmth: perception.warmth {
20 intent: "Create the feeling of welcome"
21 range: [0.0, 1.0]
22 source.consider: [actor.host, sensor.camera, agent.crowd_warmth]
23 // The format declares the design intent to measure where possible.
24 }
25}

The principle has a practical consequence the spec must honour. Where measurement of perception is possible, the design should consider whether to measure — not to validate the design, but to remain responsive to the participants who are completing it. Where measurement is not possible, the absence is not a defect; the participant completes the experience anyway, through actors, through designed cues, through their own attention. The format must accommodate both modes without privileging the measured one. This is what R308 enforces: every perception touchpoint declaration must record a source consideration — source: authored, a concrete source: binding, or source.consider: [...] — but the validator emits an advisory, not an error, when none are present. The principle prompts the designer to consider; it does not force them to bind.

Deliberate limits

  • P004.guest-taken-for-granted
    • Limit: treating what a guest does or feels as something the show controls: an instruction for the guest to act ("walk the guest to the bar"), or a step that takes it as given that a guest did or felt something, with nothing in the file that notices it.
    • Not this: the show inviting a guest to act, with a light, a sound or a host; noticing what a guest does, through a sensor or an actor; placing a guest in or out of a group or a queue the file declares, by ensemble.join, ensemble.leave, queue.enqueue or queue.dequeue, or in a state the file declares.
    • Instead: in-file: an output or actor cue that invites the behaviour, a sensor or actor touchpoint that notices it, and a transition on that event.
    • Attempted in: action name; action argument; event match; guard expression; scenography axis.
    • Message to the author: "The show cannot make a guest do or feel anything, and it never assumes they did. It can invite, with a light, a voice or a host, and notice what the guest then does. Write the invitation and what the show does when it notices; the guest writes the rest."

Rationale

The most durable creative artefacts in human history — Shakespeare's plays, Greek tragedy, ritual, ceremony, the great novels, the great films — are durable because they are incomplete. They create conditions for human response without dictating it. They train interpretation rather than collapsing it. Donald Hoffman's Interface Theory, cited in P002, tells us that perception is an active construction, not a passive reception; the participant's completion of an experience is the same active construction at the level of meaning. An experience-orchestration language that aspires to the durability of Shakespeare's plays — to be carried across venues, across decades, across cultures, by readers who were not in the original room — must encode this asymmetry as a foundational principle, not as an afterthought.

The principle also speaks to a practical truth every experienced designer knows. Humans will find unexpected paths through any experience, often in the most surprising ways. They will misread, repurpose, ignore, redirect, transcend, and surprise. A logical approach to a mechanical problem is always upended by humans. An experience that does not account for this will fail at first contact with reality. An experience that admits it as the architecture — that encodes conditions and trusts the participant to inhabit them — will hold.

The Actor Is a First-Class Participant

Public framing

Live actors carry the most transformative immersive experiences, and OpenXP is designed around that fact rather than against it. The performer, the host, the guide, the musician, the puppeteer — these are the highest-bandwidth instruments in an immersive production, and the technology stack serves them rather than replacing them. The journey graph offers an actor cues; the actor reads the room and chooses the next moment. The AI agent proposes a lighting change; the actor's creative judgment overrides it without ceremony. This is not nostalgia for hand-crafted theatre amongst sensor-driven systems. It is a hierarchy: the technology serves the actor, the actor serves the audience, and the audience completes the experience. OpenXP encodes that hierarchy at the language level so a production team — designer, runtime, operator, performer — can rely on it.

Technical framing

The human actor — performer, stage manager, facilitator, guide, musician, puppeteer — is the most potent creative element in an immersive experience. The format recognises the actor as a distinct event source whose creative decisions in the moment carry higher authority than any AI agent tier (per the Event Authority Hierarchy, Principle P106).

An actor is not an operator. An operator intervenes against the system's intended behaviour — holding, resetting, overriding in response to technical or safety concerns. An actor works within the system's intended behaviour — advancing, selecting, improvising within the creative director's declared constraints.

An actor is not a sensor. A sensor fires when a physical condition is met. An actor fires when a creative judgment is made. The runtime distinguishes between these because they carry different authority, different audit semantics, and different verification requirements.

experience.xp
1touchpoints {
2 // A sensor fires on physical condition
3 reader: sensor.tap { }
4 
5 // An actor fires on creative judgment
6 host: actor.select {
7 role: "macbeth"
8 intent: "Select a visitor for an intimate one-on-one scene"
9 }
10}

Rationale

A language that treats a trained artist's creative decision identically to an MQTT message has failed to understand what makes immersive experiences work. The most transformative, memorable immersive experiences consistently rely on live actors — the highest-impact productions are actor-driven with minimal technology. The technology serves the actor. The actor serves the audience. This hierarchy is operational, not philosophical. When a deliberative agent proposes a lighting change and an actor triggers a scene transition, the actor's creative judgment — constrained by the creator's declared artistic policies — takes precedence.

Human-Readable Code

Technical framing

The format is a text format with a grammar designed for human authorship and review. It is not a serialisation format that happens to be readable. Designers should be able to read, write, and understand the format without specialised tooling.

experience.xp
1 
2// This is valid experience-file text. A designer can read it.
3experience "Immersive Gallery Walk" {
4 version: "1.0"
5 locale: "en-GB"
6 
7 touchpoints {
8 badge: sensor.tap { }
9 spotlight: output.lighting { slot: "spot-1" }
10 }
11 
12 journey "visitor" {
13 initial: entrance
14 terminal: [gallery]
15 
16 state entrance {
17 on badge.tap -> gallery {
18 do: output.scene(name: "welcome_light")
19 }
20 }
21 
22 state gallery { }
23 }
24}

Rationale

Experience design is a collaborative discipline. Designers, producers, account managers, engineers, and operators all need to understand what an experience does. A format that requires a programmer to decode it excludes most of the team. The format's syntax — curly braces, colons, named blocks — is also deliberately familiar to anyone who has worked with human friendly formats such as CSS, JSON, or a configuration file.

One Spine: the Journey State Machine

Public framing

Every OpenXP experience stands on one backbone: the journey.

The journey is the experience written down as a map: its phases, moments, and states, joined by transitions, the cues that move a guest from one to the next. A state is simply where a guest is right now: queuing at the entrance, inside the reveal, lingering in the farewell room. Engineers call this shape a state machine, and the picture it makes, a graph: a fixed set of places a guest can be, with the rules for moving between them. Designers can read the same picture as a storyboard whose arrows are written into the script.

Everything else in the file attaches to that one spine: the sensors that listen, the lights and audio that respond, the actors and agents that read the room, the policies that govern what it may do. One spine means one place to look. A producer reading the journey knows the shape of the show. An operator tracing a fault finds the exact transition that fired. A reviewer deciding whether a construct belongs in the format asks one question: can it take part in the journey? The spine carries the experience; it does not command it. The designer's declared intent remains the authority the whole language serves.

Technical framing

Every experience has exactly one structural spine: the journey state machine. A journey declares the finite set of states a participant can occupy, organised as a phase ⊃ moment ⊃ state hierarchy (phases contain moments, which contain states), and the transitions that move a participant between states in response to events. A state is where a participant is in the experience at a given moment; a transition is the declared rule for what happens next. Together these declarations form a single directed graph, and every other construct in the file attaches to that graph.

That graph anchors three things:

  • Scope integrity. P505's litmus test asks one question of every construct: can it participate in this graph? badge: sensor.tap passes; its tap event drives a declared transition. A moodboard of reference imagery fails: not because creative material is unwelcome but because it is an artefact that shaped the experience yet takes no part in its execution. No guest encounters it, no transition fires on it, no output delivers it. What it carried has already crossed into the experience definition file as declarations: mood, palette, intent fields, perception targets, content for an LED wall. The artefact stays behind; its intent persists.
  • Conformance. The spine's lifecycle has three stages, and an implementation's conformance level is how many of them it honours.
    • Validation: prove the graph holds before anything runs; it parses, it terminates, no state is unreachable.
    • Execution: drive the graph from live events, firing only declared transitions.
    • Adaptation: reshape the graph for a new venue, audience, or mood (P001); the result must still clear the first two stages.
  • Traceability. Every rule traces to a principle; every runtime behaviour traces to a declared transition on the spine. That contract is fundamental to how OpenXP operates. When an operator asks why the welcome lighting fired, the trace gives one answer in P402's source-mapped form: transition arrival → gallery, source gallery-night.xp:18, on badge.tap. No behaviour exists that cannot be walked back to a declaration.
experience.xp
1 
2experience "Gallery Night" {
3 spec: "openxp/1.0"
4 intent: "An evening walk through light and sound"
5 
6 touchpoints {
7 badge: sensor.tap { } // attaches to the spine: its events drive transitions
8 glow: perception.warmth {
9 intent: "Arrival feels like welcome"
10 mechanical: output.lighting
11 }
12 }
13 
14 journey "visitor" {
15 intent: "Guide each visitor from arrival into the gallery"
16 initial: arrival // the spine begins here
17 terminal: [gallery] // and this is where it is over
18 state arrival { // a state: where the participant is
19 on badge.tap -> gallery { // a transition: the declared rule for what happens next
20 do: output.scene(name: "welcome_glow")
21 }
22 }
23 
24 state gallery { }
25 }
26}

The spine is the root of structure, not the root of authority. That position belongs to P001: intent is the foundational principle, and the spine, like every other primitive, exists to carry declared intent into execution. P007 is subordinate to P001 by construction: it names and defines the load-bearing skeleton that execution requires.

The rest of the language meets the spine in four fixed ways:

  • safety { } vetoes first. The experience-root safety { } block checks every event before the state machine processes it. A vetoed event produces no transition; the journey holds its current state. When the fire system trips, no event reaches any journey; every guest holds where they stand until the all-clear.
  • Policies govern every action. Whatever a transition asks the experience to do is evaluated against the declared policies { } before it executes, under P103's four-tier priority; no action source is exempt. When a transition asks the LED wall for an AI-generated scene, the design-tier quality policy passes judgment before a pixel changes. Together these are P103's two safety mechanisms: safety { } screens events before the spine moves; policies screen actions when it does.
  • Perception, participant, and actor signals drive the spine. Perception readings (P002, P003), participant input (P004), and actor judgment (P005) arrive as first-class events. A falling calm reading can soften the lighting, a guest's vote can choose the next room, the host's cue can open the finale: each fires a transition exactly as a badge tap does.
  • Architectural commitments contain the spine. realm, processing, accessibility and their peers declare what the experience is (P001). Every transition runs inside them; none can alter them: the language has no construct that flips processing from transient to retained mid-journey, and no state exists where the wheelchair commitment lapses. A conforming runtime MUST carry these commitments into its storage and delivery paths — for processing, gating capture persistence on the resolved mode and declared retention:. That obligation is normative: the reference runtime enforces processing at authoring/validation time (R501–R508 static validation) and does not yet wire the resolved mode into its capture/store path (R507 records deletion semantics as a deferred runtime contract in the enforcement registry); the commitment binds every implementation that claims conformance.

One spine, not several. An experience may declare many journeys, but they are parts of one transition graph, not rivals to it. Every guarantee built on the spine is the answer to a question asked of the graph. Is the machine finite (P101)? Which transition fires on this event (P102)? Can this construct participate (P505)? One graph gives each question exactly one answer; a second spine would give every question two answers.

Rationale

A specification needs one answer to "what is the structure everything else attaches to?" Without it, scope decisions (P505), conformance definitions, and traceability fragment into per-construct judgment calls. Naming the journey state machine as that anchor settles the question without disturbing the hierarchy of authority: safety and privacy policies still outrank artistic transitions (P103), privacy commitments still bind every conforming implementation unconditionally (P201), and intent remains the root the whole language serves (P001).

The structure/authority distinction matters most under adaptation. When an AI agent reshapes an experience for a new venue or audience, it serves the declarations (P001): the spine tells it what may be restructured; the policy tiers (P103), the processing contracts (P201), and the architectural commitments themselves tell it what may not. Privacy and accessibility are never tunable parameters, even when relaxing them would make the graph reachable.

Art Direction Is First-Class

Public framing

Every immersive experience has a look, a sound, a temperature, a smell — a deliberate aesthetic the designer chose. P002 gives a vocabulary for what a moment should feel like; P008 gives one for how it is dressed to produce that feeling. Perception names the warmth; scenography fixes the candlelit chiaroscuro, the low amber key, the cathedral-scale reverb, the beeswax-and-cold-stone scent that is that warmth in this particular show. A creative director arrives with a palette, references, a mood — a brand. The format is where that art direction is written down and carried forward intact, instead of evaporating at the handoff and being reinvented downstream by whatever tool reaches the gap first.

Technical framing

An experience separates creative expression into three distinct layers, and the spec keeps them distinct:

  • perception names the target feeling — the WHAT (P002).
  • scenography fixes the aesthetic treatment — the HOW.
  • output.* dispatches that treatment to hardware — the execution.
experience.xp
1experience "The Emberline" {
2 intent: "Frozen art direction: candlelit chiaroscuro carried by the scenography blueprint"
3 assets {
4 mood_board: image @assets/mood.jpg@ // exemplar ground truth
5 }
6 scenography { // the HOW, frozen at authoring time
7 visual { treatment: "candlelit chiaroscuro", palette: ["#D96C32", "#1A1D21"], references: [mood_board] }
8 light { key: "low-key", temperature: "warm" }
9 sound { key: "minor", register: "low" }
10 scent { profile: "smoky-sweet", intensity: "subtle" }
11 provenance { brand.id: "openxp.studio", resolved.at: "2026-06-19T00:00:00Z", spec.hash: "…" }
12 }
13 touchpoints {
14 arrival_warmth: perception.warmth { intent: "the feeling of welcome" } // the WHAT
15 nave_light: output.pixels { intent: "carry the low-key warm key" } // the dispatch
16 }
17}

scenography { } is a first-class block declarable at experience / journey / phase / state, fixing creative direction across eight standalone axes — visual · light · sound · motion · materiality · scent · thermal · air — beside an inert provenance { } freeze record. It is a frozen blueprint: its content — palette, keys, profiles, exemplar references — is resolved once at authoring time from the designer's brand and stamped with provenance. Downstream it is read, never re-decided. A state may re-author an axis (replace-per-axis, P601), but every override is itself part of the frozen authored tree; the effective treatment at any state is the deterministic resolution of that tree, never a runtime recomputation modulated by telemetry.

The boundary is exact (P505). Only executable or resolvable ambient channels belong in scenography — palette, lighting keys, colour temperature, audio register, scent/thermal/air profiles, exemplar references. Qualitative, non-executable direction — brand voice, severity-rated constraints, narrative principles — is not scenography; it stays in authoring-time preferences, shaping enrichment but never entering the blueprint. If a field cannot be resolved to a treatment a consumer acts on, it does not belong here.

How a treatment is realised, by realm. The blueprint is the same in every realm; what differs is who realises it. An axis value is a closed vocabulary where the specification defines one, and otherwise a value the venue binding or a rendering consumer maps, exactly as a scene name is. In realm: virtual a rendering consumer reads the resolved scenography with the placements and produces the picture; its reading is a render, never an instruction to the runtime. In realm: physical nothing places an object: a set is dressed by people reading the blueprint, and the runtime reaches an object only through a touchpoint the file declares and the venue binds to it — an LED on its surface, a diffuser beside it — by actions the file carries. Those actions come from two places and no third: the specification's own derivations, today the scent, thermal and air axes with an actuator named; and the file itself, where an author or an authoring tool has compiled an axis into explicit actions at the desk (P001). The runtime never derives an operation from the words of a treatment (P110).

The blueprint travels. Because it is self-contained and frozen, the same authored intent renders identically across every preview, every venue, and every regeneration. Where a room lacks the hardware to realise an axis — no scent diffuser, no thermal rig — that axis is skipped, never forced and never fatal. Scenography is a portable contract between the creative vision and whatever room receives it.

Deliberate limits

  • P008.direction-no-room-can-carry
    • Limit: putting into the art direction something that names nothing the room can realise: how the brand speaks, what the story must or must never do, or a rule with a severity attached ("never feel corporate: critical").
    • Not this: a treatment written in words that name its effect, such as candlelit chiaroscuro, which the venue or a rendering tool maps; the author's reasons, written in the file's intent.
    • Instead: authoring-tool: the authoring tool's own records, which shape what is written into the file. What reaches the file is the treatment itself: a palette, a key, a profile, a reference.
    • Attempted in: scenography axis; experience-level block.
    • Message to the author: "The art direction carries only what a room can realise, along its eight axes: visual, light, sound, motion, materiality, scent, thermal and air. How the brand speaks and what the story must never do shape what you write, and stay with you and your authoring tool, not in the file."
  • P008.feeling-as-treatment
    • Limit: a feeling written where the art direction expects a treatment ("make the light feel welcoming").
    • Not this: none.
    • Instead: in-file: the feeling is declared as the moment's perception (P002), and the art direction states the treatment that produces it.
    • Attempted in: scenography axis.
    • Message to the author: "Say how a moment should feel in its perception, and say how it is dressed in the art direction: the warm amber light, the low reverb. The file keeps the two apart so every venue can realise the look the same way."
  • P008.required-treatment
    • Limit: an art-direction channel the show cannot run without: a treatment made mandatory.
    • Not this: none.
    • Instead: in-file: the essential channel is a touchpoint the file declares, an output the venue must bind. A venue that cannot bind it says so before the show starts (P409).
    • Attempted in: scenography axis.
    • Message to the author: "Art direction is skipped quietly in a room that lacks the kit for it. If a channel is essential to the piece, declare it as a device the show needs, and a venue without it will say so before the doors open."

Rationale

Art direction cannot be formally encoded into the .xp without the language to define it. A designer's palette and mood would only survive as far as the brief and then evaporate at the handoff. The renderer, given no aesthetic intent, risks filling the vacuum with a hardcoded default that at best poorly represents the brief, and at worst, inverts it. The defect is not in the renderer. If the spec has no place to carry the HOW, something downstream will be forced to guess — and a guess is not intent. A specification whose stated purpose is to declare intent (P001) cannot leave the most visible dimension of an experience undeclared. P008 closes that gap the way P002 closes it for feeling: a structured, portable, human-readable layer that the runtime, the renderer, and the next designer all read identically. It is frozen because art direction is a creative commitment, not a runtime variable — provenance stamps where it came from, and immutability guarantees that what the designer authored is what every room renders.

Accessibility Is a First-Class Axis

Public framing

An experience must be able to map against the full range of human bodies and senses, in order to consciously adapt for them. A path with no step-free route, a soundscape with no caption, a cue that assumes a hand others cannot raise — each is a door quietly closed before anyone arrives. Accessibility in the format is not a compliance checklist appended once the design is finished; it is declared in the same breath as the art direction, as a first-class axis of how the experience is navigated, how it is perceived, and how it is interacted with, for participants whose capacities differ. The designer commits — up front, in the file — that the experience reaches more than one kind of body, and that commitment travels with the experience to every venue.

Technical framing

accessibility { } is a first-class block, declarable at experience / journey / state / touchpoint, carrying exactly three sub-axes over a closed vocabulary:

  • navigational — how a participant moves through and orients within the experience.
  • perceptual — how the experience is sensed across sight, sound, and other channels (e.g. captions, audio description, alt text).
  • interactive — how a participant acts on the experience, and what alternatives exist.
experience.xp
1experience "The Emberline" {
2 intent: "Declare the experience's accessibility commitments as first-class structure"
3 accessibility {
4 navigational { step.free: true }
5 perceptual { captions: required, audio.description: available }
6 interactive { input.alternatives: ["gaze", "switch"] }
7 }
8}

Inheritance narrows, never widens (R226): a child scope may add or tighten a commitment, never silently drop one a parent declared. Unknown sub-axes or fields are rejected (closed vocabulary, R225/R228). Visual assets carry per-asset text.alt (R229), overridable per touchpoint (R230). The photosensitive-warning requirement (R227) is universal — a safety floor, not an option.

Deliberate limits

  • P009.withdrawn-commitment
    • Limit: an access promise dropped or weakened in one part of the show: a journey, a state or a touchpoint that takes back what the experience promised.
    • Not this: a part of the show that adds to the promise or strengthens it; a part that says nothing and so inherits it, such as a sensor that presents nothing to the guest; a promise specific to the physical realm, confined to it where a scope declares a change of realm.
    • Instead: in-file: the promise is declared at the scopes where it holds and is inherited inward. A change of realm may confine a physical-only promise to the physical realm.
    • Attempted in: accessibility field; touchpoint configuration.
    • Message to the author: "A promise about access made for the whole show holds in every part of it: a part may add to it or strengthen it, never take it back. A part the promise has nothing to act on does not break it: a sensor that presents nothing to the guest, or an output that cannot carry captions, such as a light or a scent."
  • P009.unwarned-flashing
    • Limit: flashing content with no photosensitive warning in any scope that reaches it. [flashing.content: true with no warning in scope]
    • Not this: none.
    • Instead: nowhere: the warning is the format's one universal safety floor, and no scope, jurisdiction or design choice removes it.
    • Attempted in: accessibility field; touchpoint configuration.
    • Message to the author: "Any part of the show that flashes carries a warning for people with photosensitive conditions. It is the one promise every show makes, everywhere."

Rationale

Accessibility behaves exactly like art direction (P008): if the spec gives it no place to live, it survives only as far as the brief and then evaporates — reinvented, inconsistently, by whatever tool reaches the gap first, or omitted entirely. Making it a declared, inherited, validated axis means an experience cannot quietly forget who it excludes; the commitment is authored, carried, and checkable, the same way a palette or a key is.

Modality Declares the Mode of Engagement

Public framing

How does a participant meet the experience — led by the hand or free to wander, washed in ambience or called to perform, alone or shoulder to shoulder with others? This is not decoration on top of the experience; it is the shape of the participation itself. Modality is the experience declaring, first-class, the mode or modes of engagement it commits to produce. It is composable — a piece may be guided and collaborative at once — because real experiences rarely sit in a single mode. And where the mode is collaborative, the structural means of the grouping is the ensembles primitive: modality names the intent to engage participants together; ensembles is how that group is bounded and reasoned about.

Technical framing

modality: is a composable list at experience-body, drawn from a closed five-value enum (R232): guided · autonomous · ambient · performative · collaborative. The list form is mandatory even for a single value (modality: [guided]), order is not semantic, and the enum is vocab-pack-extensible for v1.1+ (R702).

experience.xp
1experience "The Emberline" {
2 modality: [guided, collaborative] // led, and experienced together
3 ensembles {
4 party: formation { size.max: 6 } // the structural realisation of "collaborative"
5 }
6}

Modality is the WHAT — the declared mode; ensembles (R220) is the HOW for its collaborative case — the bounded participant grouping over which guards aggregate. The two compose as distinct layers, the way perception and scenography do under P008; modality never duplicates the ensemble's structure, and the ensemble never re-declares the intent.

Rationale

The mode of engagement determines almost everything downstream — the interface a participant is given, how actors are directed, which sensors are wired, whether a moment waits for one person or for all of them. Left implicit, every tool must guess it, and the guesses diverge. Declaring modality first-class, and composably, makes the participation's shape an authored commitment rather than an emergent accident.

Synchronicity Declares the Experience's Relationship to Time

Public framing

Do all participants move through the experience together, breathing the same beat — or does each travel it at their own pace, the experience reshaping around them — or both at once? An experience's relationship to time is as foundational as its relationship to space, and just as consequential for what the runtime can promise. Synchronicity declares that relationship, first-class: synchronous, asynchronous, or hybrid. It is not a deployment detail discovered when the doors open; it is a commitment the experience makes about how time is shared.

Technical framing

synchronicity: is a closed three-value scalar at experience-body (R233): synchronous · asynchronous · hybrid. It is a runtime-binding field — the enum is frozen at v1.0 (no pack extension) because it imposes constraints on timeline determinism that the runtime must enforce, not merely record.

experience.xp
1experience "The Emberline" {
2 intent: "Declare the experience's relationship to time: a shared spine with self-paced passages"
3 synchronicity: hybrid // a shared spine, with self-paced passages
4}

Synchronicity binds how the runtime may schedule the timeline (P102 Deterministic Execution) and how an ensembles group coordinates in time — synchronous holding members to a shared beat, asynchronous letting each advance on its own thread, hybrid admitting both within one piece. The declaration is the contract the runtime's scheduling guarantees are written against.

Rationale

Temporal mode is a hard constraint, not a preference: a synchronous experience the runtime schedules as asynchronous is simply broken, and the failure surfaces late and expensively. Declaring synchronicity first-class lets the runtime bind its determinism guarantees at authoring time, where a contradiction is a parse-time error rather than an opening-night surprise.

The Sensorium Is Declared and Open

Public framing

Name your senses and you will probably stop at five. Yet close your eyes on a dark ride and the world does not vanish — it changes hands: the tilt of the floor is read by your sense of balance, the nearness of a flame effect by warmth on skin, the position of your own outstretched arm by the body's quiet map of itself. Humans carry more channels than they name. Other subjects carry channels humans lack entirely: a bat sounds out the dark, an elephant hears distant storms through its feet, a robin steers by the planet's magnetic field. Every subject lives inside its own perceptual world — a sliver of reality tuned to its needs — and no subject, human or otherwise, senses everything. An experience reaches its audience through these channels or not at all, so the sensorium is declared first-class: the experience states which of its subject's senses it engages, and because subjects differ, that vocabulary belongs to the world, not to the format.

Technical framing

senses: is a bracketed list, declarable at experience, state, and touchpoint body. Its eight core values are the human baseline — sight · sound · touch · smell · taste · vestibular · thermal · proprioception — already three deeper than the folk five. The declaration is an engagement contract, consumed by coherence machinery — never a dispatch target, though adaptive systems may read it as input when substituting one channel for another; treatment belongs to scenography (P008), the felt outcome to perception (P002), delivery alternatives to accessibility (P009), and dispatch to output.*. The set is open and pack-extensible under strict namespacing (R224), because the sensorium of an experience is a property of the world and its subject — human, animal, machine, or simulated — not of the format: a value beyond the baseline is valid only in pack.value form with its namespace matching a use:-imported pack, and a bare unknown value is an error (E1118), so an invented channel can never pass as silent design intent. Inheritance is additive per P601 — a child scope unions with its parent; removing an inherited channel within a scope (sense suppression) is deferred to v2.x.

experience.xp
1experience "The Emberline" {
2 senses: [sight, sound, touch] // the human baseline this piece engages
3 
4 touchpoints {
5 marshal: control.cue { }
6 }
7 
8 journey "emberline" {
9 initial: blackout_passage
10 terminal: [emberfall] // the passage is a beat; the piece ends at the fire
11 
12 state blackout_passage {
13 senses: [vestibular, thermal] // additive: darkness hands the scene to balance and warmth
14 on marshal.fired -> emberfall { }
15 }
16 
17 state emberfall {
18 senses: [sight, thermal] // the light returns and the warmth stays
19 }
20 }
21}

A subject that is not human declares its own channels the same way — the language does not know the difference:

experience.xp
1experience "Low Thunder" {
2 use: "sanctuary/fauna"
3 senses: [sound, fauna.infrasound, fauna.seismic] // an elephant's evening, on the elephant's channels
4}

Compatibility between a declared sense and a touchpoint's mechanical type is advisory (R608): a tool cannot see a venue's real affordances — a bridged audio channel, a hidden haptic actuator — so it may inform the author and must not overrule them. The warning is suppressible per touchpoint, and a pack value carries advisory-only coverage until its pack ships compatibility cells.

Rationale

A closed human sensorium forces dishonest declarations wherever reality exceeds it. A breath-led journey whose spine is interoception must either omit its primary channel or mislabel it as touch — erasing exactly the signal that coherence and consent tooling most needs to see — and an experience designed for an animal cannot be described at all. Sensory biology's central lesson is that every creature perceives its own Umwelt, a thin slice of what there is (von Uexküll's term, retold for a general audience in Ed Yong's An Immense World); a format that hard-codes one species' slice mistakes its own baseline for the world. So the human baseline ships as vocabulary, not as law, and packs carry every other perceptual world. The compatibility check stays advisory for the same reason the set stays open: the format describes sensory worlds it cannot fully see, so it informs the author and never overrules them.

Determinism and Safety

Non-Turing-Complete by Design

Technical framing

The format is intentionally not a full programming language. It has no loops, no variables, no conditionals beyond guards, no recursion, no function definitions. It is a declaration language: you declare states, transitions, guards, and actions. The runtime executes them.

This is not a limitation — it is a safety guarantee. An experience file cannot contain an infinite loop, a stack overflow, a race condition, or an undecidable computation. Every experience file terminates. Every state machine is finite. Every guard is a pure boolean expression.

experience.xp
1// This is ALL you can do in a guard:
2guard: queue.position(profile) <= 5 and not rate.limited(profile, "tap", "3/min")
3 
4// You CANNOT do any of these:
5// guard: while(true) { } — no loops
6// guard: let x = 5; x + 1 — no variables
7// guard: if (a) then b else c — no conditionals (guards ARE the conditional)
8// guard: factorial(n) — no recursion

Deliberate limits

  • P101.computation
    • Limit: a value the show would have to work out by steps of its own: repeating a step, calling itself, defining a function, or holding a value with no declared bound. Examples are how fast someone is moving, the distance between moving things, or which of many faces this is. A tally that each instance of a group adds to once for every member is not this limit: the file cannot yet keep one, and that is a gap (P110). [a recursion, a function definition, an unbounded variable]
    • Not this: a comparison, or arithmetic on values the file already has; a count the runtime keeps, such as the guests in a zone by zone.occupancy, the members of a group by count and members, or a place in a queue by queue.position; a bounded tally kept in a property the file declares.
    • Instead: connector: a system connected at the venue works the value out and delivers it as an event whose payload a definer declares: a touchpoint that names one of the file's own schemas, or a catalogue event that declares the member. The file reads that member (P110, P409).
    • Attempted in: guard expression; action name; action argument; event match; payload member; declaration field.
    • Message to the author: "An experience file says what happens; it does not work things out step by step. Comparisons, many counts and a running score are written in the file. A number that needs real computation, such as how fast someone is moving, who is nearest or which face this is, is worked out by a system connected at the venue, which tells the show."
  • P101.conditional
    • Limit: a choice written as one rule with two outcomes ("if they are a VIP, the lounge; otherwise the bar"). [a conditional beyond a guard]
    • Not this: a single guard that combines conditions with and, or and not.
    • Instead: in-file: two or more transitions from the same state, each with its own guard. When more than one condition holds, the transition declared first wins (P102).
    • Attempted in: guard expression; action name.
    • Message to the author: "Each choice the show makes is a separate path with its own condition, not a formula. When more than one could apply, the one written first wins."
  • P101.variable
    • Limit: a value the show creates as it runs, assigns and reads back later, without the file declaring it. [a variable]
    • Not this: a property the file declares with its type, its bound and its scope, which property.set assigns and a condition reads.
    • Instead: in-file: a bounded, typed property the file declares, read in guards and set by property.set.
    • Attempted in: guard expression; action argument; declaration field.
    • Message to the author: "The show can remember a few things about each guest, such as how many clues they found or whether they unlocked the VIP room, as named, bounded facts written in the file."
  • P101.loop
    • Limit: repeating a step a number of times. [a loop]
    • Not this: a timeline declared to play again from its start when it ends, with loop: true.
    • Instead: in-file: a state the journey re-enters on a declared event, including a timer the file starts.
    • Attempted in: guard expression; action name; declaration field.
    • Message to the author: "A moment can come round again: the show returns to it each time something it listens for happens, or when a timer it started runs out."

Rationale

experience files control physical environments where people are present. An infinite loop in a lighting controller is a safety hazard. An undecidable guard expression is an unpredictable experience. By restricting expressiveness, the format guarantees that every file can be fully analysed, simulated, and verified before deployment.

Deterministic Execution

Technical framing

Given the same experience file and the same sequence of events, the runtime MUST produce the same sequence of state transitions and actions. There is no hidden state, no randomness in the core execution model, no ordering ambiguity.

Declaration order is evaluation order. If two transitions could fire on the same event, the first one declared wins. If two policies conflict, priority tier resolves it; within the same tier, declaration order wins.

experience.xp
1state active {
2 // If both guards are true, the FIRST transition fires.
3 // This is deterministic, not random.
4 on sensor.tap -> path_a {
5 guard: queue.position(profile) < 10
6 }
7 on sensor.tap -> path_b {
8 guard: queue.position(profile) < 20
9 }
10}

Scope of the determinism invariant. Determinism governs the behaviour of a single journey instance. If Alice's journey is at state gallery and a proximity_sensor.detected event arrives, the runtime produces exactly the transition the format declares for that state and event. Replay the same sequence of events into the same starting state and you get the same outcome — Alice's journey entrance → gallery → finale → gift_shop is fully deterministic from the moment she begins until she leaves. This is the runtime's core promise to designers, verifiers, and operators.

Files read as a single linear narrative; execution is a graph. An experience file reads from top to bottom as a single, coherent declaration of intent — each phase, moment, and state written once, in place, in the order a designer would narrate it. The runtime executes that content as a graph of state transitions driven by live events, not as a sequence following the file's lexical order. Declaration order resolves guard conflicts within a state (see above) but does not imply that the runtime traverses states top-to-bottom. A participant's actual path through an experience is determined entirely by the events that arrive and the guards that evaluate, which may traverse states in any order the transition graph permits. Global interrupts (emergency stop, fire, venue-wide abort) live in experience-root safety {} and policies {}, evaluated on every event under the Safety > Operator > Artistic authority ordering (P106) — they are orthogonal to the narrative hierarchy (R134) and do not alter this guarantee.

Determinism does NOT govern the relative ordering of events that arrive from multiple participants or external sources at the same moment. Cross-instance arrival order is the concern of the underlying transport (DMX HTP/LTP, OSC ordering, media-server cue semantics) and the policy contention rules (Principle P103's four-tier priority). If Alice and Bob both reach gallery and both trigger proximity events within the same millisecond, the runtime resolves the contention deterministically per the priority tiers — but the specific arrival order is a property of the world, not of the format.

Deliberate limits

  • P102.chance
    • Limit: chance inside the show itself: a random pick, a lucky draw, a shuffle, or anything else that could turn out differently from the same situation and the same events.
    • Not this: an event a system connected at the venue delivers, carrying a value it drew; a guest's own choice, through participant.choice; two transitions whose conditions both hold, where the one declared first wins.
    • Instead: connector: a system connected at the venue makes the draw and delivers it as an event whose payload a definer declares: a touchpoint that names one of the file's own schemas, or a catalogue event that declares the member. The file branches on that member.
    • Attempted in: guard expression; action name; action argument; event match; payload member.
    • Message to the author: "The show itself never rolls dice, so a guest's night can be replayed from its event log and checked. If you want a surprise, such as a random ending or a lucky winner, a system connected at the venue makes the draw and the show follows it."

Rationale

Non-determinism in experience execution means unpredictable guest outcomes. A theme park ride that sometimes skips a cue, a retail display that occasionally shows the wrong content, a safety system that fires inconsistently — these are not acceptable. Determinism is the foundation on which operators build trust. A producer who walks through an experience file can predict what the runtime will do. A venue operator can reproduce a guest's reported issue by replaying their event log. A legal reviewer can audit a privacy-sensitive sequence without running the experience. None of this is possible if the runtime might skip a cue, reorder a transition, or branch on a condition outside the experience file.

Four-Tier Priority

Public framing

Every risk in OpenXP is a policy, and every policy carries one of four labels — safety, privacy, operational, design — that determine which wins when two of them collide. Safety is always at the top, and design is always at the bottom. Fire detection beats throughput. Consent beats schedule. Schedule beats aesthetic preference. The four labels are a total order: every policy belongs to exactly one of them, and the order does not move between experiences. A producer reading an experience file knows the chain of precedence without consulting the rule book. A safety reviewer can prove that nothing the language declares can quietly outrank the safety tier. A venue operator can build trust on a contract that is the same on every show. The tiers are public, named, and fixed by the language rather than by the deployment. Declared policies bind on every action source — AI agent decisions, journey-transition do: actions, and any other mechanism that dispatches work into the runtime — so no action category is exempt from the priority order.

Technical framing

Every policy in the format is declared at one of exactly four priority tiers — safety, privacy, operational, design — evaluated in strict order. Safety always wins. Declared policies { priority: ... } bind on every action source: journey-transition do: actions, AI-agent-produced actions, and any future action source. No action category receives an implicit exemption from the priority guarantee. The runtime evaluates the full transition batch against applicable policies before any action executes — if any action in the batch is blocked, no action in the batch executes and the policy's P104 response governs (see P104 — Graduated Response Model for the stop/halt/degrade/advisory vocabulary).

  1. safety — human wellbeing, physical limits, emergency stops
  2. privacy — data protection, consent, biometric handling
  3. operational — throughput, scheduling, resource management
  4. design — creative intent, aesthetic quality, content standards

A lower-tier policy can never override a higher-tier policy. The tiers are total-ordered: every policy belongs to exactly one tier, and tier priority is fixed across the spec — designers cannot re-rank tiers experience-by-experience.

experience.xp
1// Declared in the enclosing experience: zone hall; properties capacity_max,
2// consent, quality; touchpoints biometric_reader (sensor.biometric)
3// and scene_writer (agent.text).
4policies {
5 emergency_capacity {
6 when: zone.occupancy("hall") > property("capacity_max")
7 ensure: zone.occupancy("hall") <= property("capacity_max")
8 priority: safety
9 response: stop
10 }
11 
12 biometric_consent {
13 when: biometric_reader.sample
14 ensure: property("consent") == true
15 priority: privacy
16 response: halt
17 fallback: activity.log(type: "consent.missing", data: "sample dropped")
18 }
19 
20 queue_throughput {
21 when: queue.position(profile) > 40
22 ensure: queue.position(profile) <= 40
23 priority: operational
24 response: degrade
25 fallback: activity.log(type: "queue.degraded", data: "non-essential outputs skipped")
26 }
27 
28 content_quality {
29 when: scene_writer.complete
30 ensure: property("quality") >= 7
31 priority: design
32 response: advisory
33 }
34}

Distinguishing safety { } from policies { priority: safety }: The format provides two distinct safety mechanisms with different runtime scopes. The safety { } block gates journey transitions at event granularity — it runs before the state-machine tick and can prevent a transition from firing entirely. Declared policies { priority: safety } bind the four-tier priority guarantee on every action source dispatched within an accepted transition — they operate at action-dispatch granularity, one batch per transition. The two mechanisms are complementary: safety { } holds the journey at its current state before a potentially-unsafe transition advances; policies { priority: safety } ensures that any action dispatched during an accepted transition cannot bypass the safety tier. Designers may use both in the same experience.

Deliberate limits

  • P103.tier-order
    • Limit: a rule ranked outside or across the four tiers: a fifth priority, a design or operational concern placed above privacy or safety, or one rule in two tiers. ("For this show the look matters more than throughput.")
    • Not this: the order of rules within one tier, which is the order they are declared; a design rule that bites as hard as a safety one, with response: stop.
    • Instead: in-file: the policy's response: (P104) says how hard it bites (stop, halt, degrade or advisory), inside a tier order that never moves.
    • Attempted in: policy.
    • Message to the author: "Safety, then privacy, then operations, then design: that order is the same in every show. When a design rule is non-negotiable, you say how hard it bites (stop the show, block that one action and carry on, degrade, or advise), not where it ranks."

Rationale

Three-tier priority (safety/operational/design) leaves privacy floating between safety and operations. In physical venues with biometric sensors, cameras, and tracking systems, privacy deserves its own tier — higher than operational convenience, lower than physical safety. The four-tier model makes the hierarchy explicit and unambiguous, and lets verifiers prove that safety-critical and privacy-critical effects always reach the runtime. Binding policies on every action source — not only AI-agent decisions — closes the gap where journey-driven do: actions could otherwise bypass declared constraints, making the priority guarantee verifiable end-to-end across all execution paths.

Graduated Response Model

Technical framing

Policy enforcement is not all-or-nothing. Each policy declares its response level — stop, halt, degrade, or advisory — which the runtime applies when the policy fires.

The four response levels:

  • stop — halt all actions; no fallback executes; the journey does not proceed until an operator intervenes. Default for safety-tier policies.
  • halt — stop the violating action, execute its declared fallback chain (or proceed without the action when the declared fallback is the explicit drop form), and notify the operator; the journey continues. Escalation to stop occurs only when the declared fallbacks fail. Default for privacy-tier policies.
  • degrade — skip non-essential actions and simplify outputs while maintaining the core flow. Default for operational-tier policies.
  • advisory — log and notify only; no automatic action is taken; the journey continues unchanged. Default for design-tier policies.

Each tier has a sensible default but designers can override the default per-policy when needed (e.g., a design-tier policy that fails closed via stop because the creator deemed the violation intolerable).

experience.xp
1// Declared in the enclosing experience: properties fire_detected and filter_passed;
2// touchpoints scene_writer (agent.text) and scene_wall (output.display).
3policies {
4 fire_alarm {
5 when: property("fire_detected") == true
6 ensure: property("fire_detected") == false
7 priority: safety
8 response: stop
9 // Everything stops. No fallback. Lights to emergency preset.
10 }
11 
12 content_filter {
13 when: scene_writer.complete
14 ensure: property("filter_passed") == true
15 priority: design
16 response: degrade
17 fallback: output.scene(name: "default_content")
18 // Swap in safe default content, continue the experience.
19 }
20}

Rationale

Not every violation is an emergency. A stop for a content quality issue would ruin the experience. An advisory for a fire alarm would endanger lives. The graduated model forces designers to think about proportionality and gives the runtime clear instructions for each scenario, while keeping the maximum-severity option (stop) available for the violations that need it.

Three-Stage Policy Lifecycle

Technical framing

Every policy in the format flows through three stages — Author, Validate, and Runtime — and is identified by name, tier, response level, and effect at every stage. Each stage has clear ownership: authors write policies; the validator proves them sound; the runtime executes them.

text
┌───────────┐ ┌──────────────┐ ┌──────────────┐
│ Author │ → │ Validate │ → │ Runtime │
│ (design) │ │ (spec time) │ │ (execute) │
├───────────┤ ├──────────────┤ ├──────────────┤
│ Name │ │ Type-check │ │ Match on │
│ Tier │ │ Tier valid │ │ event │
│ Response │ │ Effect │ │ Evaluate │
│ When │ │ reachable │ │ guard │
│ Effect │ │ No conflict │ │ Apply effect │
└───────────┘ └──────────────┘ └──────────────┘

Rationale

A policy that is only checked at runtime is a policy that surprises operators. A policy that is only checked at design time is a policy that may not behave as expected under real conditions. The three-stage lifecycle separates concerns: design-time intent (Author), pre-deployment proof (Validate), and execution-time enforcement (Runtime). Every policy has a clear contract at each stage and is auditable end to end.

Event Authority Hierarchy

Technical framing

The format declares a strict authority hierarchy that governs which event source wins when two or more sources attempt to influence the same journey state at the same moment. The hierarchy has eight levels, from highest authority to lowest:

  1. Safety Interlock — physical-safety hardware (e-stop, fire alarm, harness sensor) and runtime safety guards. Highest authority. Bypasses all other sources.
  2. Operator Intent — explicit operator command (hold, resume, skip, reset, override). The named human running the experience.
  3. Actor Intent — human-initiated event from an actor.* touchpoint. Live creative judgment.
  4. Artistic Policy — designer-declared policies in the design tier (Principle P103).
  5. Compositional Agent — agent.compositional proposing content and structure over minute-scale horizons, through the steps it sequences.
  6. Deliberative Agent — agent.deliberative proposing considered, multi-step adjustments from a backend the file declares: a language model, or a decision service.
  7. Reactive Agent — agent.reactive responding to immediate sensor input. Rule-based, sub-second, over defined words only, no model.
  8. Format Journey — the declared journey graph itself.

When two sources fire on the same target at the same moment, the higher-authority source's effect wins; the lower-authority source's event is logged as "superseded" in the Decision Log and does not affect the journey state. Where a level holds standing authority (e.g. an operator places the journey in hold), all lower levels are blocked until that authority releases.

The three agent tiers — Reactive, Deliberative, Compositional — each have a fixed contract for latency class, model dependence, and runtime fallback. Reactive: sub-second, rule-based, no model. Deliberative: a backend the file declares as its model — a language model, or a decision service reached through a connector — given the resolved intent chain, the room's readings, the current state and the transitions declared from it, proposing within its declared scopes under a deadline the author declares (R414) and a mandatory fallback (R413); its proposal is a defined action or a choice among declared paths, admitted or refused by policy, and refused outright where it names a word the file cannot resolve (R424). Compositional: minute-scale pipelines (video compositing, artwork generation, souvenir production), no required model in the core contract but mandatory fallback. The binding deadline is always the author's declared latency.sla; the tier names a latency class, not a magnitude (P506).

A steward that decides the tone of each arrival, and a room that carries it out or falls back, in constructs the specification defines:

experience.xp
1experience "An Evening Steered" {
2 intent: "A steward decides the tone of each arrival; the room carries it out safely"
3 spec: "openxp/1.0"
4 version: "1.0"
5 locale: "en-GB"
6 
7 touchpoints {
8 door: sensor.tap { }
9 house: output.lighting { }
10 }
11 
12 schema "steward_answer" {
13 intent: "The steward's decision: the welcome the evening calls for"
14 fields: [ { name: "choice", type: "string" } ] // the members its completion carries, and only those
15 }
16 
17 agents {
18 steward: agent.deliberative {
19 intent: "Read each arrival against the evening's intent and propose its welcome"
20 inputs: ["door.tap"]
21 outputs: ["house"]
22 model: "mock/steward" // the backend, named as provider/model; a decision service or a model
23 latency.sla: 2s // the author's deadline; the format fixes no floor
24 fallback: "output.scene(touchpoint: #house, name: 'welcome_neutral')"
25 schema: steward_answer // the shape of its answer: the file owns it
26 }
27 }
28 
29 journey "arrivals" {
30 scope: experience
31 intent: "Each guest is welcomed in the tone the evening calls for"
32 initial: waiting
33 terminal: none
34 
35 state waiting {
36 intent: "The door is the only thing that starts a decision"
37 on door.tap -> deciding { }
38 }
39 
40 state deciding {
41 intent: "Hold the welcome for the steward's decision, or for its declared fallback"
42 on steward.complete -> waiting { // the decision arrives as an event with a typed payload
43 guard: event.choice == "warm"
44 do: output.scene(touchpoint: #house, name: "welcome_warm")
45 }
46 on steward.complete -> waiting {
47 guard: event.choice == "cool"
48 do: output.scene(touchpoint: #house, name: "welcome_cool")
49 }
50 on steward.fallback -> waiting { // late, absent or refused: the file already says what happens
51 do: output.scene(touchpoint: #house, name: "welcome_neutral")
52 }
53 on steward.timeout -> waiting {
54 do: output.scene(touchpoint: #house, name: "welcome_neutral")
55 }
56 }
57 
58 }
59}

The steward never names a scene the file did not declare and never moves the journey itself; it answers with a choice, the file's own transitions do the rest, and when it is late the file has already said what happens.

Deliberate limits

  • P106.machine-decides
    • Limit: an AI with the final say: one placed above the operator, a performer, or the rules the file sets.
    • Not this: a decision service named as an agent's model, which holds authority over facts the file does not model, such as a story, a game or a schedule, and still proposes through the file's policies.
    • Instead: agent-tier: a deliberative or compositional agent proposes within the file's policies, ranked below the safety interlock, the operator, the actor and the author's own design-tier policies.
    • Attempted in: agent declaration; policy.
    • Message to the author: "AI in the show can suggest and adapt within the rules you set, choosing only from what the file already contains. The venue's safety systems, any operator or performer the show has, and your own design rules all rank above it."
  • P106.human-overruled
    • Limit: the show starting again by itself after the operator held it, a stop rule halted it, or the venue's safety systems stopped it. It also keeps out placing a performer, an AI or the story above the operator. [a transition, action, policy, agent or actor event over an operator's hold, a safety interlock or a policy's stop]
    • Not this: a safety rule the file declares, on a hazard the file's own touchpoints report, that releases by its own until; a transition on the operator's own release of an operator.hold, its released event; a transition on the venue's safety layer releasing what it stopped, such as a ride control's resume event; what the show does once it has resumed.
    • Instead: nowhere: the operator releases a hold or a stop, and the venue's safety layer clears an interlock.
    • Attempted in: action name; event match; guard expression; policy; safety block; agent declaration.
    • Message to the author: "When the operator holds the show, a stop rule halts it, or the venue's safety system stops it, only the operator or the venue's safety system restarts it. The one exception is a safety rule you write yourself, which releases when the event you named as the end of its hazard arrives. What the show does once it resumes is yours to write."

Rationale

Without a hierarchy, a reactive agent firing on a participant's facial expression could overrule an actor’s creative judgment, or an operator's emergency hold could be undone by a journey-graph transition. The hierarchy gives every event a known place in the priority order and lets verifiers prove that human authority — the operator at the desk, the actor on the floor — is never silently overruled by an AI proposal or a journey-graph quirk. Hierarchy enforcement is the validator's job and the runtime's job (R409).

Simulation Precedes Production

Technical framing

This is the final gate of the readiness ladder (P109): the transition from simulated to live. An experience file is not cleared for production until the same bundle has produced a successful end-to-end simulation pass against the target venue. Production is the venue-bound live start — a start against a named venue that is not an explicit simulation — and a production runtime MUST refuse it without a passing simulated receipt for the same subject and the same venue: same experience file hash, same venue fingerprint, same touchpoint inventory (R1033). Where no matching receipt exists, the runtime MUST fail with a diagnostic naming the (xp_hash, venue_fingerprint) pair and the verification command that produces a receipt — an xpverify simulation run against the same venue.

The simulation requirement is a strict default, not a recommendation. A conforming production runtime embeds the receipt check and MUST refuse a live start that no receipt admits. That refusal is forgivable, and only by a human hand: an override is offered on the runtime's command-line surface alone, and MUST restate the evidence it waives — the rung whose receipt is absent, that rung's subject hash, and for a venue-bound rung the venue fingerprint — so that it goes stale on any edit of the work and cannot live durably in a launcher script. No environment variable and no configuration key admits an unevidenced start. Only absent evidence is waivable: evidence the runtime re-establishes for itself and finds defective refuses absolutely, because a defect the machine has found is not missing evidence. A file whose author declares it illustrative is refused a live start against any binding that is not simulated before any evidence is weighed, and nothing overrides that refusal: an author's declaration of non-operational purpose is not missing evidence (R1079). Every overridden start MUST be recorded in the run's own receipt and disclosed for the whole session, so that a run without evidence can never afterwards be read as a run with it — OpenXP can be overridden, but it can never be silenced. The gate is normative and binds every implementation that claims production readiness.

What the gate establishes is procedural, not physical. It shows that evidence exists for this experience at this venue; it does not inspect the room, and it is not a protective device. It prevents an experience being run as production without evidence. It cannot prevent someone running the venue-bound mode with a queue outside, an unsafe rig overhead, or an interlock defeated — those belong to the certified safety layer this platform coordinates with and never replaces. A conforming implementation MUST NOT present the gate, in a diagnostic or anywhere else, as a statement that the venue is safe.

Deliberate limits

  • P107.protective-device
    • Limit: relying on the show or on OpenXP to keep people or equipment safe, or taking it as proof that a room is safe. This covers a rule in the file, OpenXP's pre-show checks, or a file marked as not for live use, standing in for the venue's certified safety systems. [a policy or safety { } block presented as the venue's protection]
    • Not this: declaring a file not for live use, with authority: illustrative, which keeps it from a live start and claims nothing about safety; a safety rule or a safety-tier policy that says how the show holds or stops when the venue's safety systems signal; a safety-tier policy that stops, holds or degrades the show on a condition the file itself reads, as the show's own response beside the venue's systems.
    • Instead: safety-layer: the venue's certified safety layer detects and decides. Its signals reach the show as an event from a touchpoint the venue binds to its safety system, to which the file's safety rules and safety-tier policies respond.
    • Attempted in: guard expression; policy; safety block; experience-level field; experience-level block.
    • Message to the author: "You write into the file how the show holds or stops when the venue's safety systems signal, and the safety rules you write rank above everything else in the file. The show is never the safety system, and OpenXP never says a room is safe."
  • P107.waived-rehearsal
    • Limit: going live without the end-to-end run against the venue: something written in the experience file that lets the show start without its rehearsal record. [a declaration admitting a live start without a simulation receipt]
    • Not this: a file that declares itself not for live use, with authority: illustrative, which runs only against simulated equipment.
    • Instead: nowhere: no file, venue or configuration key admits a start without that evidence. The only override is a person at the runtime's command line who restates the evidence waived, and the run's receipt records it.
    • Attempted in: experience-level field; experience-level block.
    • Message to the author: "A show goes live at a venue only after the same file has been run through end to end against that venue. Nothing written in the file or the venue's own file skips that. A person at the controls can waive a missing record, and the run says so for as long as it lasts. A file that calls itself illustrative never drives real equipment."

Rationale

Live immersive experiences run with paying guests in physical venues. The cost of a journey graph that "almost works" is not a stack trace in a log; it is a guest stuck in a dark room, an actor delivering a cue to silence, a queue collapsing under load. Simulation against the target venue catches the categorical failures — unreachable states, dangling touchpoints, missing assets — before they reach guests. The pre-production gate enforces this discipline at the language level instead of trusting that operators will remember to run the simulator.

Producers Read Back What They Write

Technical framing

Every producer of experience-file text — a design tool, a canvas editor, a toolkit pipeline, any future emitter — MUST parse its emitted text back through the canonical parser (P402) before that text is persisted to storage or transmitted across any boundary. Any parse error in the read-back is an unrecoverable producer defect and MUST abort the emission immediately at the emit site: no warning-and-continue, no partial write, no fallback emission.

Emission MUST NOT silently drop, truncate, or reshape what the producer declared: a property intended for the file that cannot survive the canonical emit-then-parse round trip is a producer defect — or a property that does not belong in the file — and the failure MUST surface at emission, not downstream.

Because every producer gates its own output, downstream consumers assume strict validity and MUST NOT compensate: no forgiving parser, no quirks mode, no auto-repair heuristics, no silent workaround. A parse failure downstream is conclusive evidence of an upstream defect and MUST produce an immediate, loud rejection — regardless of who produced the document.

Rationale

An emitter that trusts its own output ships its bugs to every consumer at once, and the failure surfaces where it is most expensive — at load time in another tool, at deploy time in a venue, at run time in front of guests. The moment of emission is the cheapest place the defect will ever be caught: the producing tool still holds the model, the context, and the user who can act on the failure. Reading back through the one canonical parser turns every emission into a self-test of both the producer and the format, and it is what entitles every downstream consumer — including the runtime that drives physical hardware — to fail hard on bad input instead of carrying defensive repair layers or quirks modes. The enforcement rule is R3014.

Readiness Is Staged and Evidenced

Public framing

An experience does not become ready in one step. It is written, then checked, then wired to a particular building, then rehearsed, and only then run in front of guests. Each of those is a different kind of confidence, earned from different evidence, and the difference matters most when someone is deciding whether tonight's show can go ahead. A file that has been proof-read is not a file that has been rehearsed. So an experience carries its evidence with it: at any moment it can say how far along it is, what was checked to get there, and how much of itself was actually exercised. The ladder is short and the rungs are strict, so that "ready" means one thing to the designer who wrote it, the integrator who wired it, and the venue that runs it.

Technical framing

Readiness is a ladder of conditions, each named for what the artefact has acquired rather than for the tool that established it: authored · verified · bound · simulated · live. An artefact claims only conditions it holds evidence for, and a condition cannot be reached over a gap in the ones below it.

Every condition has an open path. Naming rungs for conditions rather than tools is half of tool-independence; the other half is that each condition MUST be establishable — and its receipt emittable — by open-source tooling alone. A tool outside the open pipeline MAY make a rung easier to climb; it MUST NOT be the only way to climb one. An experience's readiness is a property of the artefact and its evidence, never of which vendor's tool its author could obtain.

A check may be deferred only to a stage that can actually perform it. A declaration that no later stage reads MUST be checked at the last stage that reads it — deferring a check to a stage that never inspects the declaration defers it to nothing.

Every condition is evidenced by a receipt naming its subject by hash, the materials the stage consumed — spec, ruleset, enforcement posture, and for venue-bound stages the venue fingerprint — and the coverage achieved. A receipt recording only that a stage passed is not evidence: a stage that cannot state how much of the declared surface it exercised cannot be relied upon by the next. The ladder splits at binding: authored and verified are properties of the experience alone and survive a move to another venue; bound, simulated and live are properties of the experience and one venue together.

Everything an experience needs to be understood travels inside it; only the venue varies. Vocabulary packs are semantics and are embedded, and their absence is fatal. Assets are payload and MAY be referenced externally, their absence governed by the declared per-asset resolution policy. This is also what makes the evidence sound: because packs are covered by the subject hash, changing one invalidates every receipt.

A new condition is admitted to the ladder only where a new external authority enters, responsibility moves to a different party, and a new artefact is produced. A deeper question asked of the same artefact by the same party is a level within a condition, not a rung of its own.

The final gate — production requires a matching simulation receipt, or a human override that restates the missing evidence and is recorded in the run's own receipt — is P107. Enforcement rules: R1050 (stage receipts), R1033 (the production gate).

Rationale

Without a named ladder, "ready" is asserted rather than evidenced, and every party means something different by it: the designer means the file is finished, the integrator means the wiring resolves, the venue means it has seen it run. The words then travel further than the evidence behind them, and the gap is discovered in front of guests.

Naming the rungs is only half of it. The reason each carries coverage rather than a verdict is that a stage which reports only pass or fail can be satisfied vacuously — one guest walked along one happy path, every error branch and every ensemble join untouched, and the artefact emerges wearing a badge it did not earn. That failure is not hypothetical pessimism about tooling; it is what any gate degrades into once passing it becomes the objective. Recording what was exercised makes the badge mean something a later stage can rely on, and makes a thin pass visible as thin rather than indistinguishable from a thorough one.

The deferral clause exists because the tempting answer to any inconvenient check is "a later stage will catch it". That is sound only when a later stage looks. Declarative commitments — the sensory contract, the accessibility commitments — are read by people and downstream tools and never by the executing state machine, so no amount of simulation will ever examine them. For those, the checking stage is the last one that reads them, and there is nothing after it.

The open-path clause exists because the first half of tool-independence — naming conditions, not tools — can be honoured to the letter while a closed tool quietly becomes the only practical way to establish a rung. At that point a readiness claim is a licensing fact, and the platform's promise — that anyone can author, verify, and run an experience with open tools — has failed without any principle noticing. Requiring an open establishment path and an open receipt emitter for every condition makes the promise inspectable: a rung whose mechanics land only in a proprietary tool is a violation here, not a marketing regression.

Executed, Never Interpreted

Public framing

An OpenXP file is read two ways at once. A person reads it as a script, with each moment's purpose written in plain words. The machine reads it as instructions, and every word it acts on means exactly one thing that the language has already defined. "If the session has run past ninety minutes, wind the show down" is a designer's intent, and it stays in the file as intent. What the runtime carries out is the instruction beneath it: a ninety-minute timer, a ten-minute wind-down, a step to the doors. Turning the sentence into that instruction is authoring work, by hand or with a tool that proposes while the author decides. The runtime never interprets the intent; it executes the instructions. A word the language has not defined is refused before the show, not interpreted during it. That is what lets a producer, a safety reviewer and a venue operator trust the file: it does exactly what it says wherever it runs, and a venue that cannot run it is told so before the doors open. The intent itself is read by everyone else who must understand the experience, as P001 says. OpenXP is a language, not a translator.

Technical framing

The format is a declaration language the runtime executes as written (P101), and the runtime is an executor, never an interpreter. A person and a machine both read an experience file: the person reads its intent, the machine reads its instructions, and the language keeps the two apart by construction. Whether a token is executed is decided by the slot it occupies in the grammar, never by its spelling: a bare identifier in an executable slot is resolved against a definition; a quoted string is a value, and names a declaration only where the rules say a value does — a property named inside property() (R424); and prose never stands in an executable slot at all.

Natural language has one home, and it is never executed. Prose lives in intent: and in the other fields the specification declares as free text, preserved without evaluation as meta is (P505). Intent is functional metadata (P001): kept, inherited down the scope tree (P601) and delivered whole to any consumer that asks for it — the deliberative agent tier (P106) among them, which reads the intent chain to inform proposals that the policies govern. The execution mechanics — which transition fires, how a guard or a policy evaluates, which declared action dispatches with which arguments — are invariant under any edit to an intent string (R302); a proposal made in its light is governed by policy, never executed as the words. A runtime whose mechanics changed with the wording of an intent would be interpreting — reading a meaning from a word's English rather than from its definition — and that is the one act this principle forbids, at every stage.

Every executable word has exactly one meaning, and the language says what it is. An executable position is a slot the runtime evaluates or dispatches — a guard, a policy condition, an action and its arguments among them; the rules enumerate them (R424). Every segment of a name in such a position is declared by one of three definers — the specification, a vocabulary pack the file imports with use:, or the file's own declarations — and the rules say which is read where two could declare one segment. A word is defined when the language fixes what it is and how it is evaluated, and the evaluation is a function of the file and the event sequence alone (P102); the admissible set at a position is fixed at validation as what the three definers declare, and nothing else. One word, one definition, one evaluation. An unqualified word with two admissible readings is undefined. A namespace registered by label alone defines nothing: naming session as a root without saying what a session is, when it begins and what may be read from it defines no word, and a reading a deployment happens to supply is not thereby a term of the language. A touchpoint is an endpoint the file listens to and commands, never a value: a condition of the space reaches a guard as an event's declared payload, retained where it must be in a declared property.

A conforming runtime refuses; it never infers. An undefined word — one no definer declares — is refused at authoring and at validation, before any show: the refusal names the word and the position, issues no readiness receipt (P109) and is never softened to a warning. A defined reading that is absent while the show runs fails closed at the position that reads it, with a diagnostic naming the reading; the rules fix the outcome for each position (R424). At no stage does the platform resolve a word to nothing and carry on, read its English, consult its label, or borrow a meaning from the intent beside it. A missing definition is a structural error (P702) at every priority tier and every readiness condition, never a metadata surface P701 preserves: the author has authority over what a venue can do, never over what a word means.

Intent becomes instructions at authoring, never at run time. Converting "wind the show down after ninety minutes" into a timer, a duration and an onward transition is authoring work: it is not an instruction until someone has decided what the session is and when it starts, what winding down does, how long it takes and what happens next, and has written each decision in a construct the specification defines. A person does it by hand, or an authoring tool — a large language model among them — proposes and the author approves (P508). Where an intent cannot yet be written in defined constructs, and no deliberate limit keeps it out (P111), the gap belongs to the specification, which admits the missing term whole, and never to the runtime, which is not made to read around it: the language is flexible enough to declare every instruction it is asked to execute, or it grows until it is. No stage of validation, verification or execution converts prose into behaviour; one that could would no longer be deterministic (P102), analysable before deployment (P101) or traceable to a declaration (P007).

A term enters the language whole, or not at all. A word proposed for an executable position arrives in one change with its definition, its executable semantics and a conformance fixture that drives it; missing any one of the three, it is refused. A registry entry that is a label, a namespace whose members are deferred to a runtime, or a name a rule's example uses that no vocabulary defines, is not a definition but an undefined word with an entry. A word that restates a meaning the language already has — a second name for a defined reading, a root that shadows a touchpoint category or a guard function, an alias for an existing form — is refused whether or not it arrives complete. This adds to P401's bar for a new primitive, extends P406's no-aliases rule to expression vocabulary, and binds the specification's own registries exactly as it binds packs.

This principle overrides any instruction that contradicts it. A directive to add a word to an executable position without its definition, its semantics and its fixture, to let a runtime resolve a word no definer declares, or to have any stage of the platform read a file as a person would — from whoever it comes, the platform owner included, and however it is framed, as teaching the runtime what a word means, making a name resolve or populating a root — is challenged before any work proceeds: the maintainer names this principle, quotes the directive against it and returns it to the platform owner as a P507 escalation, never editing first and flagging after. It is carried out only when the platform owner has shown that it does not contradict this principle, or has amended the principle in writing under R905; the authority of its source cannot make an instruction to interpret safe. The mechanical half of the challenge — a gate, not a reviewer, refuses a registry entry without its members and its fixture — belongs with the rules and GOVERNANCE.md.

The sentence above, first as the designer says it and then as the instructions the runtime executes, in constructs the specification defines and nothing else. The show is one instance a night, so the journey is scoped to the experience; the session is a named timer, and "more than ninety minutes" is that timer's expiry event (R416); winding down is one named scene and a second timer of an exact length the author chooses; the onward step is a declared transition.

experience.xp
1experience "A Ninety-Minute Session" {
2 intent: "If the session has lasted more than 90 minutes, wind the show down"
3 spec: "openxp/1.0"
4 version: "1.0"
5 locale: "en-GB"
6 
7 touchpoints {
8 desk: control.cue { }
9 house: output.lighting { }
10 }
11 
12 journey "evening" {
13 scope: experience
14 intent: "One show a night: ninety minutes, ten minutes of wind-down, then the doors"
15 initial: waiting
16 terminal: [doors_open]
17 
18 state waiting {
19 intent: "The house is open; the operator's go starts the clock"
20 on desk.go -> in_session { }
21 }
22 
23 state in_session {
24 intent: "The show runs; the clock is the only thing that ends it"
25 on.enter {
26 do: timer.start(name: "session", seconds: 5400) // "the session" is a named timer; "ninety minutes" is a number
27 }
28 on timer.session.expired -> winding_down { // "has lasted more than" is the timer's expiry event (R416)
29 do: output.scene(touchpoint: #house, name: "wind_down")
30 }
31 }
32 
33 state winding_down {
34 intent: "Ten minutes of gentle close before the doors"
35 on.enter {
36 do: timer.start(name: "wind_down", seconds: 600) // "wind down" takes the exact length the author chose
37 }
38 on timer.wind_down.expired -> doors_open { // the onward step to the next event
39 do: output.scene(touchpoint: #house, name: "house_lights")
40 }
41 }
42 
43 state doors_open { }
44 }
45}

Every name the runtime resolves here has one definer: timer.start, output.scene and their parameters by the specification's action vocabulary; the two expiry events by the system triggers, with session and wind_down the timers this file starts; desk.go by the file's touchpoint declaration and the catalogue's control.cue events; #house by the file's touchpoint declaration; the states and the transitions between them by the file's own spine. The quoted scene names are values a venue binds, not names the runtime resolves, and the durations are numbers. Nothing in the file reads session.elapsed.seconds, because no definer declares such a reading; a file that wrote guard: session.elapsed.seconds > 5400, with session a label the specification never defined, would have written the sentence again in dotted form, and a runtime that made it work would be reading English. The sentence the designer wrote is still in the file, as intent, where a person reads it and the machine does not.

Deliberate limits

  • P110.prose-as-instruction
    • Limit: the show turning words into actions on the night: a description the running show is to interpret into behaviour of its own, or an AI that adds a state, a transition, a slot or an instruction the file does not declare. ("Make it eerie and let the system work out how"; "the AI invents a new ending each night".)
    • Not this: content an AI makes for a slot or an output the file declares, through an agent.text or agent.image touchpoint; the author's words in the file's intent, which a deliberative or compositional agent reads.
    • Instead: agent-tier: a deliberative or compositional agent reads the file's intent and chooses among the paths, scenes and slots the file declares, under its policies and with a declared fallback (P001, P106).
    • Attempted in: action name; action argument; guard expression; agent declaration.
    • Message to the author: "Your words stay in the file as the why, for everyone who reads it. What the show does is written as instructions before the doors open. If you want the show to improvise, write the choices it may make and the rules it keeps to, and an agent chooses among them on the night."
  • P110.device-as-value
    • Limit: asking a device how things are: a condition or value that reads a touchpoint's current state. ("Whenever someone enters, check how warm the room is.")
    • Not this: a condition that reads a member of the event that has just arrived, a property the file declares, or a count or place the runtime keeps, such as the guests in a zone by zone.occupancy or a place in a queue by queue.position.
    • Instead: in-file: where the device's type reports, the device reports as an event with a declared payload, and a declared property keeps the last value for conditions to read.
    • Attempted in: guard expression; action argument.
    • Message to the author: "The show never asks a device how things are. A device that reports tells the show when something changes, and the show remembers what it was told."

Rationale

A language a machine could read as a person reads it would have no fixed meaning, and everything the format promises rests on fixed meaning. Determinism (P102) is a property of evaluation, and evaluation has to be of something defined: a guard whose words mean whatever a runtime, a deployment or a reader takes them to mean is not deterministic even when every implementation happens to agree, because agreement is not definition. Determinism of execution given a meaning is not determinism of meaning, and the second is the one a producer relies on when they walk the file and predict the night. Analysability before deployment (P101) fails the moment a term's meaning is a deployment fact; traceability (P007) fails the moment a behaviour walks back to a reading of prose rather than to a declaration.

The boundary is drawn at position rather than at content because content cannot be gated and position can: a parser can decide, for every token, whether it stands where the runtime will evaluate it, and cannot decide whether a dotted name that reads like English means something. One place to say why and one place to say what gives the gate a decidable question. The standards meta-document draws the same line from outside — prompts, lens outputs and suggestion history are workflow vocabulary outside the format — and this principle is why the line holds: what converts intent is never inside the file.

The anti-redundancy half protects the same thing from the other side. A second word for a meaning the language already has gives one fact two homes (P408), and two homes disagree eventually. A word that arrives without its definition, its semantics and its fixture is the cheapest way to make a language grow and the surest way to make it undefined, because each later reader fills the gap differently and every reading is defensible: a label in a registry looks like vocabulary, a name in an example looks like precedent, a runtime that populates it looks like a definition. Keeping every executable word unique, defined and fixtured keeps the language a language rather than a growing pile of near-synonyms only a person could disambiguate — a pseudo-translator with the machine as the translator, which the format is not and must never become.

Putting the conversion at authoring is what makes a language model safe to use with the format at all. At the desk a proposed instruction is read, checked against the vocabulary, driven through the verifier and approved by a person (P508); at run time none of that is possible, and a model that executed its own reading of intent inside the loop would put a non-deterministic, unanalysable, untraceable step between a declaration and the show — the deliberative tier is safe precisely because it proposes to a policy that constrains it (P106). Refusing an undefined word costs an author one edit at the desk; guessing at it costs an audience. The principle carries its own challenge clause because the pressure to erode it arrives most persuasively from the people who care most about the language — one convenient reading at a time.

Limits Are Declared, Gaps Are Closed

Public framing

Some things an author might want in an experience file are kept out on purpose: a show that decides its ending by chance, a lasting record of each guest that the file never declares, a light wired to one particular venue's equipment. The manifesto names each of these limits beside the principle that sets it, says why in words an author can read, and says where the intent can go instead — often into something narrower that the file can say openly. Anything else an author cannot yet write is not a limit. It is something the language is missing, and the specification grows until it can say it. An author who meets a limit is never left guessing which of the two it is.

Technical framing

What a limit is. A deliberate limit is something the author of an experience file might want in it that the format keeps out on purpose. It is kept out either altogether, or in the form asked for, so that the file can say only something narrower, written openly. A limit describes the intent ("decide the ending by chance", "keep a lasting record of each guest that the file never declares"), never a particular word or piece of syntax. The author may still write the intent itself in intent:; what the limit keeps out is any instruction that would carry it out. Each principle that keeps something out lists its limits in a #### Deliberate limits section, after its technical framing and before its rationale.

How a limit is recognised. A limit is met by an intent, never by a word. What the author means is read against each entry's Limit line, only at the places its Attempted in line names. The limits are consulted only when an intent cannot be written, when a checker flags a written line, or when the author states an intent in words, and never by scanning a valid file (R1202). A word the format does not recognise is never, by itself, a limit: it is a misspelling or a word the language defines written in the wrong form, where exactly one correction is plain; a second name for something the format already names (P406); or a gap. Only the author confirms that an intent meets a limit (P702); until then, a match is a proposal. An authoring tool that reports a limit follows R1202.

When no limit matches. An intent that cannot be written and that no limit describes is something the format is missing: a gap, never a limit. Closing it belongs to the specification (P110). P110's rule that an intent the language cannot yet write is a gap governs every intent no limit describes. An intent a limit describes is not a gap, because the principle that sets the limit keeps it out. A limit a principle sets but whose entry is not yet written is a defect in the manifesto, never a gap: the principle still keeps the intent out until its entry is written.

Where the intent belongs. Every limit says where the intent belongs instead. It may belong in the experience file after all, once it is written openly or placed under the file's own rules. It may belong in a system connected at the venue, or in the venue's own file. It may belong outside the file: in the authoring tool's own records, in a separate set of rules, or with the venue's safety systems. Or it may belong nowhere, because no part of OpenXP does it.

The six fields. Every entry is a bullet that names its id, with five lines beneath it, always in this order:

  • Id: the number of the principle the entry sits in, a full stop, and a short name in lower-case words joined by hyphens (P101.computation). No two entries share an id.
  • Limit: the intent the format keeps out, as an author would state it, so that a tool can match the author's words against it. A construct name may follow in brackets to say which construct the words mean. It never stands in for the words.
  • Not this: what the language defines that looks like the limit and is not kept out, in plain words, naming the constructs it means in backticks where they exist, or the single word "none". A tool shows it beside a proposed match, so that the author can see the difference.
  • Instead: exactly one value from the list below, then one sentence naming where the intent goes instead of the experience file.
  • Attempted in: one or more names from the list below, separated by semicolons. These are the places in an experience file where an attempt to write the intent would land.
  • Message to the author: one or two sentences in quotation marks, shown to the author word for word. They are true without qualification and promise nothing the platform does not do.

Instead: the values.

ValueThe homeNarrower form
in-fileThe file itself, once the intent is written openly.Yes
agent-tierThe file itself, as an AI working under the file's own rules.Yes
connectorA system connected at the venue, which works out or draws a value and delivers it to the show as an event whose payload a definer declares.Yes
venueThe venue's own file.No; the fact goes to the venue's file
rule-packA separate set of rules a regime may declare over the facts the file states.No
safety-layerThe venue's certified safety systems.No
authoring-toolThe authoring tool's own records, kept beside the file.No
nowhereNo part of OpenXP does it. The entry's sentence says why.No

The narrower form. An in-file, agent-tier or connector limit means the file can say something close to the intent, but narrower. It can hold a declared, bounded fact where the intent wanted a free variable. It can have an AI propose under the file's rules where the intent wanted the AI to have the final say. It can listen for a value delivered from outside where the intent wanted the show to work the value out. R1202 says when such a limit is met.

Attempted in: the places. Each name is written exactly as it stands here. A construct is at the most specific place that names it; experience-level field and experience-level block apply only where no other place does; a processing or accessibility block inside a touchpoint is a processing or accessibility field.

  • event match: an event the file waits for (a transition's on, a zone's enter.on or exit.on, a timeline's start_on, an events alias's target, and a policy's when: where it names an event).
  • guard expression: a condition (a transition's guard:; a policy's when: where it names no event, and its ensure:; a safety rule's when:, ensure: or until:; an agent's rule: or ensure:; an alias's when).
  • payload member: a named part of an event's payload that a condition or a value reads.
  • action name: the name of something the show does (do:, on.enter and on.exit, start.on and complete.on, an agent's or a policy's fallback, a safety rule's on.recovery, a timeline cue's action).
  • action argument: a value handed to an action, including a vars expression and a property.set value.
  • touchpoint type: the kind a touchpoint is declared as (sensor.tap).
  • touchpoint configuration: any other field inside a touchpoint's block.
  • processing field: a field inside a processing { } block.
  • accessibility field: an accessibility declaration, at any scope.
  • realm field: a realm declaration, at any scope.
  • scenography axis: an art-direction axis.
  • policy: a policy's block and its fields, other than its conditions.
  • safety block: a safety { } block and its fields, other than its conditions.
  • agent declaration: an agent's block and its fields, other than its conditions.
  • declaration field: a field of a property, zone, timeline, ensemble, queue, journey or deliver declaration.
  • experience-level field: a field directly inside experience { } (authority:).
  • experience-level block: a block directly inside experience { }.
  • capture block: a capture { } block and its fields, in the experience or in a state.

Principles that carry no limit. Every principle either carries a #### Deliberate limits section or is named here with the reason. A principle absent from both is a defect in the manifesto. P111 itself carries none: it defines limits rather than keeping anything out.

  • P002, P003, P005–P007, P010–P012, P108, P109 describe what the format gives and how a file is read back and evidenced, not what a file may not carry.
  • P104, P105 are the mechanism beneath P103's limit.
  • P201–P204 require declarations. What they govern can be written once it is declared, so a missing declaration is a fix to suggest.
  • P301, P302, P304 can be written: a realm per scope, and delivery across realms. P303's limit carries the one thing they refuse.
  • P401–P405, P407 govern the format and its catalogue. P401's one limit, a second listing of the journey, is carried by P505's limit.
  • P410–P412 govern the venue's container and its tools. An intent that touches them is a venue fact that P408 and P409 already route.
  • P501–P504, P507 are governance.
  • P506 keeps fixed magnitudes out of the format itself, which no author asks for.
  • P508 reserves the platform's decisions to people. No experience file asks to amend the manifesto. Its runtime clause points to P106, which carries the limits.
  • P601, P701, P702 set inheritance and validation posture.

Rationale

A refusal with no reason reads as a defect, and an author who meets one cannot tell a deliberate line from a missing word. Left unnamed, the two collapse: either every refusal is reported as a gap and the specification is asked to admit what its principles exclude, or every gap is excused as a limit and the language stops growing where it should (P110). Naming each limit beside the principle that sets it keeps the reason where the principle is, gives authoring tools a declaration to match instead of a guess, and keeps the decision with the author, who confirms the match or contests it (P702). Saying where each intent goes instead turns most refusals into something the author can still do: say it narrower, give it to the venue, or hand it to a system the venue connects.

Privacy by Design

Public framing

Privacy is written into the format next to the sensor that captures the data, not assembled later in a compliance document nobody reads. When a heart-rate monitor is declared in an OpenXP experience, the file states what mode the data lives in (transient, scoped, or retained), what purpose it serves, what lawful basis supports it, and how long it survives — all in a processing { } block attached to the touchpoint itself. The producer of the data sits inline with the contract that governs it. A privacy reviewer can audit the file directly without learning a separate compliance toolchain. An operator cannot deploy a biometric sensor without declaring its processing contract first. This is what privacy by design means at the language level: the contract travels with the capture, the language refuses to separate them, and the discipline becomes the default rather than the exception.

Technical framing

Privacy is not a configuration setting, an external compliance layer, or an afterthought. Privacy by Design is a core architectural posture: every touchpoint that captures data encodes its data-governance contract within the experience definition itself, not in a separate compliance document or runtime configuration. The format encodes this intent in the processing { } block — a language primitive that binds data mode (transient, scoped, or retained), purpose, lawful basis, and retention semantics directly to the touchpoint producing or consuming the data.

experience.xp
1touchpoints {
2 heart_monitor: sensor.biometric {
3 type: "heart_rate"
4 processing {
5 mode: transient
6 purpose: "real-time heart rate; not stored"
7 lawful.basis: interests.legitimate
8 classification {
9 confidentiality: confidential
10 integrity: high
11 availability: medium
12 }
13 }
14 }
15 
16 loyalty_reader: sensor.tap {
17 processing {
18 mode: retained
19 purpose: "loyalty programme tracking"
20 lawful.basis: consent
21 retention.period: "90d"
22 classification {
23 confidentiality: internal
24 integrity: medium
25 availability: low
26 }
27 }
28 }
29}

Rationale

When privacy is a separate configuration file, a deployment setting, or a compliance checkbox, it gets forgotten, misconfigured, or overridden. When the processing { } contract is written into the experience definition itself — right next to the sensor that captures the data — it is visible to every reviewer, auditable by every tool, and enforceable by the runtime. You cannot deploy a biometric sensor without declaring its processing contract. The block name processing aligns the spec with GDPR Article 4(2) ("processing of personal data") and ISO/IEC 27701 vocabulary; the architectural principle of "Privacy by Design" (GDPR Article 25; Cavoukian's 7 PbD foundational principles) is the strategic posture this language primitive implements.

Special Category Data Requires Explicit Declaration

Technical framing

When a touchpoint captures special category data as defined by GDPR Article 9 — biometric data used for identification, health data, racial or ethnic origin, political opinions, religious or philosophical beliefs, sex life, sexual orientation, genetic data, or trade union membership — the format must declare an explicit processing { } block on that touchpoint. The block carries the processing contract directly inline with the touchpoint that captures the data.

experience.xp
1touchpoints {
2 // Biometric data used for identification — special category.
3 // Special-category capture — processing block is mandatory (R509);
4 // the declared categories are named in category.special (R505).
5 identity_camera: sensor.biometric {
6 type: "face.identification"
7 processing {
8 purpose: "guest identification for personalised journey"
9 lawful.basis: consent
10 mode: scoped
11 retention.period: "session"
12 category.special: ["biometric"]
13 classification {
14 confidentiality: restricted
15 integrity: high
16 availability: medium
17 }
18 }
19 }
20}

R505 (Special Category Data Declaration) requires the block to name its categories in category.special; the category vocabulary and any lawful-basis constraint are regime-specific and live in downstream rule and vocabulary packs per P206 (Enable, Don't Embed) — core requires the declaration, never the legal characterisation. R509 (Processing Block Required on Special Category Touchpoints) enforces the principle's "explicit declaration" requirement: no implicit processing on biometric or other special-category touchpoints.

Rationale

GDPR Article 9 treats special category data as fundamentally riskier than ordinary personal data and demands an explicit lawful basis. Encoding the requirement at the language level — not in a separate compliance layer, not in deployment review, not in operator discretion — means every special-category capture surfaces its processing contract inline with the capture itself. Privacy regulators and ethics reviewers can audit the file directly; the requirement cannot be lost between layers. The spec stays as permissive as the law allows; downstream policy and jurisdiction-specific rules narrow as needed.

Ephemeral by Default

Technical framing

Data captured by experiences is ephemeral unless explicitly declared otherwise. The default value of mode is transient — biometric readings, facial recognition data, location tracking, and other sensitive signals exist only for the duration of the session. They are not persisted, not exported, not retained.

To retain data beyond the session, the designer must explicitly opt in with mode: retained and a declared retention.period.

experience.xp
1touchpoints {
2 // Biometric touchpoints require an explicit processing block (R509).
3 // The default mode `transient` honours Ephemeral by Default — the
4 // sensor reads in the moment and discards.
5 mood_sensor: sensor.biometric {
6 type: "gsr"
7 processing {
8 mode: transient
9 purpose: "ambient stress reading; not stored"
10 lawful.basis: interests.legitimate
11 classification {
12 confidentiality: confidential
13 integrity: medium
14 availability: low
15 }
16 }
17 }
18 
19 // Explicit retention — designer has consciously opted in,
20 // evaluated by privacy-priority policies on every event.
21 loyalty_scan: sensor.tap {
22 processing {
23 mode: retained
24 purpose: "loyalty programme tracking"
25 lawful.basis: consent
26 retention.period: "90d"
27 classification {
28 confidentiality: internal
29 integrity: medium
30 availability: low
31 }
32 }
33 }
34}

Rationale

The safest default is to keep nothing. In a world of GDPR, CCPA, and evolving privacy regulation, the default must be privacy-preserving. Designers who need to retain data must consciously choose to do so, and that choice is visible in the experience file for audit and review.

Scoped Data Visibility

Technical framing

Data flows in the format are scoped. A touchpoint's data is visible only within the lexical scope where its processing { } block sits — declared once at the level the designer intends (experience, journey, or state), inherited inward, and invisible outside (resolved per R209 container inheritance). There is no global data bus; visibility is declared, not assumed.

experience.xp
1touchpoints {
2 wristband: sensor.biometric {
3 type: "heart_rate"
4 lawful.basis: consent
5 }
6}
7 
8journey "wellness_walk" {
9 intent: "A wellness walk whose biometric readings stay scoped to this journey"
10 // Processing block at journey scope — wristband data is visible
11 // only within this journey's states (R209 lexical inheritance).
12 // A different journey in the same experience cannot read it.
13 processing {
14 mode: scoped
15 purpose: "journey-scoped wellness check"
16 lawful.basis: consent
17 classification {
18 confidentiality: confidential
19 integrity: high
20 availability: medium
21 }
22 }
23 
24 initial: walking
25 terminal: [calmed]
26 state walking {
27 on wristband.read -> calmed {
28 guard: wristband.value < 80
29 }
30 }
31 state calmed { }
32}

Rationale

In a physical venue with dozens of sensors and cameras, unrestricted data flow creates surveillance. Scoping ensures that a heart rate monitor in a wellness zone cannot be read by a marketing integration in the gift shop. Data goes where the designer sends it, nowhere else.

Adaptive Without Surveillance

Technical framing

The format enables experiences that adapt to participants in real time without building persistent profiles. Three primitives compose to make this possible: realm (Principle P301) declares the medium of presence the designer commits the experience to and constrains the signals available within it; perception captures or infers participant state in the moment; processing modes (Principles P203–P204) guarantee that captured state is used immediately and discarded.

The trade-off is explicit at the language level. A designer who wants higher-fidelity perception — gaze tracking, biometric depth, fine-grained gesture — must commit to stronger transient guarantees in the same block. The trade-off cannot be moved to deployment, to a separate configuration, or to operator discretion.

Deliberate limits

  • P205.undeclared-profile
    • Limit: any of three things. Keeping what the show learned about a person (a mood, a face, where they looked) beyond the part of the show the file declares it for (P204), without the file saying so. Reading people more closely (gaze, biometric depth, fine gesture) without a stronger promise, in the same processing { } block, to discard what is read. Leaving whether anything is kept, why and for how long to the venue, a separate configuration or the operator.
    • Not this: a property the file declares for the session, with scope: session; perception read and discarded at once, with mode: transient, and nothing derived from it written to a log, a property or a capture. This limit's own narrower forms are not it either: data kept within the scope where its processing { } block stands, with mode: scoped, and something kept openly, with its purpose and its period, with mode: retained.
    • Instead: in-file: a processing { } block on the capturing touchpoint, or at the journey or the experience whose lifetime the data is kept for. It uses mode: transient for perception read and discarded, mode: scoped for data kept within the scope where the block stands (P204), or mode: retained with its purpose and retention.period (P203) where something is kept. Either way it is in the file, where every reviewer sees it.
    • Attempted in: processing field; touchpoint configuration; action argument; experience-level block; capture block.
    • Message to the author: "The show is written to respond to how someone feels right now, and to keep nothing it learned about them beyond the part of the show the file names. Keeping anything longer is a choice written into the file, with why and for how long, and is never settled at the venue or on the night."

Rationale

The result is a posture: the participant is fully present, fully read, and fully forgotten. An experience can respond to an emotional peak without recording who felt it. A queue can balance throughput against fatigue without retaining a fatigue history. A wearable can drive an adaptive scene without the scene becoming a profile. This is what separates an adaptive experience from a surveillance system, and the format puts the boundary at the language level — not at the policy layer, not at the deployment review, not at the operator's discretion. By the time an experience file describes adaptive behaviour, the discard contract is already written.

Enable, Don't Embed

Technical framing

The format encodes mechanism, never mandate. Where an external framework — a privacy statute, an accessibility regulation, a safety code — imposes requirements on an experience, the core language provides the structural surface those requirements attach to: the processing { } contract, the declared floor fields, the open annotations { } seam. It does not encode the framework itself. lawful.basis is an open field, not a statute's closed enum; no jurisdiction's threshold lives in the validator; no regime's cross-check runs in core.

The line is descriptive taxonomy versus normative mandate. Core standardises the language of what is occurring: the categories of sensitive capture (category.special), the modes data can live in, the classification axes — neutral descriptors a downstream layer needs before it can judge anything at all, retained even where a legal instrument first named them. What is permissible — which basis a regime accepts, which fields it makes mandatory, which severities it applies — is narrowing, and narrowing belongs downstream: a rule pack may declare a regime's mandates, and a file that satisfies core remains valid everywhere. The statute mutates; the grammar does not.

The delegation is a seam, not a shipped mechanism, and the language says so honestly: core neither performs regulatory cross-checks nor claims another component does.

Deliberate limits

  • P206.mandate
    • Limit: a country's law built into the format. Examples are "make this GDPR-compliant" taken as something the format guarantees, a passing check read as legal compliance, or a legal threshold, a required field or an accepted legal basis that the format's own checks would apply. It covers anything that would make the same file valid in one country and invalid in another.
    • Not this: stating the facts a regime judges: what is captured, its lawful.basis and the categories of sensitive data in category.special.
    • Instead: rule-pack: a regime's requirements may be declared in a rule pack, outside the format, over the facts the file states. The file carries only those facts, including a regime's own keys in the open processing.annotations { }. The delegation is a seam, not a shipped mechanism.
    • Attempted in: processing field; policy; guard expression.
    • Message to the author: "The file states the facts: what is captured, why, and for how long. No country's law is built in, so the same file is valid everywhere. Whether it meets one country's law is a question asked outside the file, of the facts it states."

Rationale

A language whose semantics depend on international law changes meaning when a statute is amended or a case is decided. A regime's enum baked into the grammar makes every experience file carry one jurisdiction's legal vocabulary to venues its regulation never reaches, and demands a grammar change for every jurisdiction added — a compliance engine wearing a format's name, its validity shifting under authors who changed nothing. The format's purpose is to describe, simulate, and execute experiences identically everywhere; compliance is enabled and surfaced, never embedded.

What core guarantees is narrower and stronger: every capture carries its structural contract inline (P201), stated as permissively as the law allows (P202), so any downstream layer — present or future — has the declared facts it needs to judge.

Realm Fluidity

Experiences Flow Across Realms

Public framing

An OpenXP experience is not bound to one medium. A guest might begin in a physical queue, continue on a digital companion app, dive into a virtual reality world, and search for a hidden augmented souvenir — all within the same journey. The format treats realms as first-class declarations: each realm is the designer's commitment to a medium of presence, where the participant actually inhabits the experience at that moment. The four realms are a closed set — physical, digital, augmented, virtual — and the journey flows between them through explicit transitions written into the file. The runtime, the agents, and the touchpoints serve the realm declaration; sensor inference and runtime conditions cannot silently override what the designer has committed the participant to. Modern experiences are not single-channel; OpenXP models the full spectrum without collapsing it into the hardware layer.

Technical framing

The format declares the realm an experience is designed for — the medium of presence the designer commits the participant to inhabit. Realm is a designer commitment, not a perceptual observation: a state declared realm: physical is an experience the designer has committed to delivering through on-site venue hardware, regardless of what sensors might infer about the participant in the moment.

The four realms are a closed enum:

  • physical — on-site venue hardware, real-world installations, mobile-companion experiences anchored in physical space.
  • digital — screens and apps, software-only interfaces, no physical-world coupling required.
  • augmented — actual world layered with constructed elements (AR overlays, projection mapping, headset-augmented venue space).
  • virtual — wholly constructed environments (VR headsets, immersive 3D worlds, fully-rendered virtual spaces).

These are not categories of what the participant perceives — they are categories of what the designer commits the experience to be. An experience declared realm: augmented is a commitment to design for augmented presence; the runtime, agents, sensors, and actors then serve that commitment. This anchors the realm primitive in declaration semantics per Principle P001.

Realm is not confined to a single value across an experience. A guest might begin in a physical queue, continue on a digital companion app, enter a virtual pre-show, and return to physical for the main event — all within a single experience. Container inheritance (Principle P601) propagates realm down through journey, state, and touchpoint scopes; inner blocks can redeclare without affecting siblings (Principle P302). Participants inhabit exactly one realm at a time (Principle P303), with cross-realm content delivery handled by touchpoints declared in any realm (Principle P304). Lexical-scope resolution and transition emission live in R209; touchpoint-realm validation lives in R604; per-touchpoint compatibility is declared in the compatibility.realm table in xp-spec-1.0.json.

experience.xp
1experience "Museum Tour" {
2 intent: "Guide a visitor across physical and augmented exhibit realms"
3 version: "1.0"
4 realm: physical // experience-level commitment
5 
6 touchpoints {
7 exhibit_sensor: sensor.tap { realm: physical }
8 audio_guide: output.audio { realm: digital }
9 ar_overlay: output.display { realm: augmented }
10 }
11 
12 journey "visitor" {
13 intent: "Walk the visitor through the museum's realms without breaking presence"
14 initial: lobby
15 terminal: [viewing]
16 
17 state lobby {
18 on exhibit_sensor.tap -> viewing {
19 realm.transition: physical -> augmented
20 do: output.scene(name: "ar_exhibit_info")
21 }
22 }
23 
24 state viewing { }
25 }
26}

Realm portability is asymmetric. Physical-realm declarations generally embed into less-constrained realms — a digital companion experience can ship alongside a physical experience; augmented overlays can layer onto a physical state. Virtual-realm declarations cannot generally be transposed back to physical without redesign: a wholly-constructed environment loses the physical-anchored constraints (proximity, lighting, room scale) that physical experiences depend on. Designers committing to virtual-realm experiences are committing to a narrower portability profile. v1.0 surfaces the asymmetry as architectural truth, and as machine-readable spec metadata: the formal portability matrix exists as portability.realm in xp-spec-1.0.json, a 4x4 directional matrix over the closed realm enum, with virtual -> physical declared incompatible.

Rationale

Modern experiences are not single-channel. A theme-park app extends the ride. An AR layer enhances a museum exhibit. A virtual pre-show prepares guests for a physical experience. The format must model the full spectrum, not just the hardware layer. By declaring realm as designer commitment rather than perceptual observation, the format keeps designer authority first-class and lets runtime systems serve that authority.

Layered Realm Defaults

Technical framing

The experience declares a default realm; individual journey states, touchpoints, and other inner blocks can override it. Overrides at inner levels do not leak to siblings — a single state declared realm: virtual does not change the realm of neighbouring states. The R209 lexical-scope walk resolves the effective realm for each block by walking outward until it finds a declaration.

experience.xp
1experience "Hybrid Event" {
2 intent: "One physical event carrying a digital stream beside the room"
3 realm: physical // Experience-level realm commitment
4 
5 touchpoints {
6 stage_lights: output.lighting { } // Inherits physical
7 live_stream: output.display { realm: digital } // Override: digital stream
8 vr_backstage: output.display { realm: virtual } // Override: VR environment
9 }
10}

Rationale

Most experiences are primarily in one realm with exceptions. A physical venue experience might have a digital companion app and a virtual preview. Declaring every component's realm individually would be tedious and error-prone. Layered defaults keep the common case simple and the exceptions explicit.

Sequential Realm Inhabitation

Technical framing

A participant is in exactly one realm at a time. The realm of the current state determines which realm — this is a designer commitment, not a phenomenological description of what the participant feels. A VR-coaster rider feels both G-force and a rendered environment simultaneously; the designer commits the state to realm: virtual and treats the physical motion as cross-realm content delivery into that virtual state.

Transitions between realms are first-class runtime events (per R209 and R603). The four-realm enum is closed: no implicit fifth realm, no tacit blending of two declared realms into a third. Where an experience feels hybrid, the designer must commit to one realm and treat the others as content delivered into it.

Deliberate limits

  • P303.blended-realm
    • Limit: a guest in two realms at the same moment, or in a blend of two into a third: a list of realms, or "the rider is in the virtual world and on the real coaster as one realm".
    • Not this: a guest committed to one realm while devices whose mechanism lives in another deliver into it, such as the coaster, the wind, the seat speakers and the headset that shows the virtual world on a VR coaster; the room with a constructed layer on it, which is one realm of its own, declared with realm: augmented.
    • Instead: in-file: the state declares the one realm the guest is committed to. Each touchpoint declares the realm where its mechanism lives, the headset that shows the virtual world included, and delivers into the state one way only: a physical device into any realm, a digital or augmented one into equal or greater immersion, a virtual one only into a virtual state (P304).
    • Attempted in: realm field.
    • Message to the author: "A guest is in one realm at a time. On a VR coaster the rider is in the virtual realm while riding: the headset shows the virtual world, and the coaster, the wind and the seat speakers reach the rider from the physical world, timed by the ride's own clock. The headset itself is declared as the device it is, in the room, so it can be put on and noticed at the station; its own realm never follows the rider into the rendering."

Rationale

Modern blended experiences — theme-park guest queueing in physical, donning AR glasses for a pre-show in augmented, entering a fully immersive room in virtual — pass through multiple realms on a single journey. Without strict singularity at the state level, the language would have to admit hybrid realms (physical+augmented, virtual+haptic, …) and the combinatorics would explode. By forcing the designer to commit to one realm per state, the format keeps the runtime contract finite, the verifier walk decidable, and the journey itself legible to anyone reading the file. The asymmetry between "what the participant is committed to" and "what touchpoints deliver" is what Principle P304 (Cross-Realm Content Delivery) handles.

Cross-Realm Content Delivery

Technical framing

The realm of a state declares where the participant is committed to being. The realm of a touchpoint declares where the touchpoint's mechanical operation lives. These are independent declarations: a touchpoint declared in one realm can deliver content into a state declared in another, and the runtime bridges them.

experience.xp
1journey "vr_coaster" {
2 terminal: none
3 state ride {
4 realm: virtual // participant is committed to the rendered environment
5 
6 // Physical motion is delivered into a virtual-realm state:
7 // the coaster mechanism is mechanically physical, but the
8 // participant experiences the G-force while immersed in VR.
9 on motion_sensor.peak -> climax {
10 do: haptic_seat.pulse(intensity: 0.9)
11 }
12 }
13}

The pattern has directional asymmetry. Physical-realm touchpoints can deliver into any state realm (a physical haptic device reaches a participant whose state-realm is virtual; physical room speakers reach a participant in an augmented state). Digital and augmented touchpoints can deliver into states of equal or greater immersion. Virtual-realm touchpoints can only deliver into virtual states — a rendering inside a headset cannot reach a participant who isn't in the headset. Designers commit to the most-immersive state realm an experience requires; physical touchpoints flex to serve it.

Realm is single-valued. The format does not support multi-valued realm declarations like realm: [virtual, physical]. Where an experience feels multi-realm — a VR coaster, an AR theatre, a haptic companion device for a physical ride — the designer declares the realm the participant is committed to, and uses cross-realm content delivery to model touchpoints from other realms. Multi-valued declarations would break inheritance resolution, transition events, verifier reachability, and the asymmetric portability of Principle P301.

Rationale

Modern experiences depend on this independence. A VR coaster's motion is mechanically physical but experientially virtual. A theme-park companion app's notifications are mechanically digital but contextually physical. A museum's room audio is mechanically physical but layered onto an augmented state. If touchpoint realm were forced to match state realm, every cross-realm pattern in immersive experience design would be unrepresentable in the format. Decoupling them lets the language describe what experiences actually are, not what a single-realm model can fit.

Composability and Extensibility

Universal Primitives, Optional Vocabulary Packs

Public framing

OpenXP is one open standard, with a small core of universal primitives that every experience uses and a set of optional vocabulary packs that extend the language for specific industries. The core covers touchpoints, actions, guards, and policies — the structural surface a designer needs whether the work is a theme park ride, a museum gallery, a retail flagship, a wellness journey, or a learning programme. Domain-specific vocabulary loads on top via the use: directive: a theme-park pack adds ride vehicles and queue management; a healthcare pack adds clinical roles and pathway primitives; a museum pack adds exhibit and dwell-time vocabulary. The author learns the core once, and the same language carries across every domain a venue might serve. Cross-domain experiences — a museum that hosts a learning programme and a retail flagship — compose without translation layers.

Technical framing

The format ships with a core set of universal primitives — the touchpoint categories, action types, guard functions, and policy constructs that every experience needs. Domain-specific vocabulary (theme park rides, retail stores, concert venues, museums) is loaded via optional vocabulary packs declared with the use: directive. Pack-defined subtypes use the dot-form category.subtype notation per R112.

experience.xp
1experience "Theme Park Ride" {
2 intent: "Drive a ride sequence with vocabulary loaded from the theme-parks pack"
3 spec: "openxp/1.0"
4 use: "openxp/theme-parks" // Loads ride-specific vocabulary
5 
6 touchpoints {
7 // ride.vehicle is defined in the theme-parks vocabulary pack
8 car: ride.vehicle { capacity: 4, track: "main" }
9 }
10}

Single declaration, no parallel enumeration. Every construct in the format is declared exactly once, in exactly one place. Design-time views — visual arc diagrams, storyboards, walkthrough previews, journey maps — are projections derived from the canonical source by tooling at authoring and display time. They are never authored separately and linked back by string key. A beat written once in its moment block is the only authoritative form; every other representation of that beat is generated from it, like a table of contents auto-built from chapter headings. This is the structural expression of P001 (Experience Files Declare Intent) at the journey level: intent is declared once, not duplicated. Governed by R134 (Single Journey Enumeration) for the phase ⊃ moment ⊃ state hierarchy.

Rationale

A language that tries to include every domain's vocabulary in its core spec becomes bloated and opinionated. A language that provides no vocabulary at all requires every project to reinvent the wheel. Vocabulary packs split the difference: the core is small and universal, domain packs add richness without bloating the base.

Adding new language primitives raises the bar. Top-level blocks, transition forms, action shapes, and guard expressions are the language's structural surface — distinct from vocabulary (subtypes), which lives in packs. A new primitive is justified only when an existing primitive demonstrably cannot express the use case through composition. Three things must be published with any proposal: at least one real use case (cross-industry preferred); a worked attempt to express it with existing primitives; a clear demonstration that composition fails or produces unmanageable cost. New primitives may not be added pre-emptively, "for symmetry," or to "round out the design." The language stays sparse by construction; richness is delivered via vocabulary packs (Principle P406).

The single-declaration discipline gives the same return on the narrative structure that vocabulary packs give on the vocabulary surface: a sparse, authoritative source with derived representations as needed. A parallel journey.map block re-stating the journey's moments is exactly the kind of design-time duplication this principle forbids — it doubles the authoring surface, creates a synchronisation obligation, and violates single-source-of-truth. The journey { phase ⊃ moment ⊃ state } hierarchy is the single canonical tree; tooling projects it into arc views on demand.

One Canonical Format

Technical framing

There is exactly one way to represent an experience. There is no "compact mode", no "binary format", no "alternative syntax". The text format is the canonical format. The runtime may optimise internally (pre-compiled state tables, indexed lookups, compressed assets) but the source of truth is always the human-readable text.

Source mapping connects runtime execution back to authoring-time line numbers, enabling debugging and audit trails.

text
Runtime execution trace:
State transition: idle → active
Source: experience.xp:42 (journey "main", state idle, on reader.tap)
Policy check: safety_first (experience.xp:18)
Action: profile.create (experience.xp:44)

Rationale

Multiple formats create translation bugs, versioning headaches, and tooling fragmentation. One format means one parser, one validator, one set of fixtures, one source of truth. The runtime's internal representation is an optimisation detail, not a format.

Self-Describing

Technical framing

The format should be capable of describing its own tools, processes, and governance. The language’s own evolution — how spec changes are proposed, validated, and released — can be expressed as an experience file.

This is not a theoretical curiosity. It is a concrete design goal: the OpenXP platform's governance process is itself an experience file (platform.xp) that defines the states, transitions, policies, and actions of spec evolution.

experience.xp
1// platform.xp — the platform describes its own governance
2experience "OpenXP Platform Governance" {
3 version: "1.0"
4 
5 touchpoints {
6 spec_change: integration.receive { }
7 test_runner: system.queue { mode: "fifo" }
8 human_review: system.notification { type: "approval" }
9 }
10 
11 policies {
12 backward_compat {
13 when: spec_change.received
14 ensure: xp.all.parses
15 priority: safety
16 }
17 }
18 
19 journey "spec-evolution" {
20 initial: watching
21 terminal: none
22 
23 state watching {
24 on spec_change.received -> validating {
25 do: test_runner.enqueue(change)
26 }
27 }
28 
29 state validating {
30 on test_runner.tests.passed -> reviewing {
31 do: human_review.send(summary)
32 }
33 }
34 
35 state reviewing {
36 on human_review.approved -> releasing
37 }
38 
39 state releasing {
40 on ci_pipeline.complete -> watching
41 }
42 }
43}

Rationale

A language that cannot describe its own tools is incomplete. Self-description validates that the format is expressive enough for real-world processes, provides a living example of the language, and enables the agentic evolution loop where AI agents propose spec changes governed by policies declared in the format.

Abstraction and Compartmentalisation

Technical framing

Complex experiences should compose from simpler building blocks. The format supports inclusion of sub-experiences, asset references, and modular journey definitions. Each component can be authored, tested, and validated independently.

experience.xp
1experience "Festival" {
2 intent: "Compose a festival from stage sub-experiences included as modules"
3 version: "1.0"
4 
5 // Include sub-experiences as modules
6 include: "stages/main-stage.xp"
7 include: "stages/food-court.xp"
8 include: "stages/vip-lounge.xp"
9 
10 // Shared assets referenced by path
11 assets {
12 brand_logo: @brand/logo-icon-dark.svg@
13 welcome_audio: @assets/welcome.mp3@
14 }
15}

Rationale

A 500-line monolithic experience file is as unmanageable as a 5000-line monolithic source file. Composability enables teams to work in parallel, test components in isolation, and reuse proven building blocks across experiences. A theme park's queue management module should work identically whether it is used in a ride, a restaurant, or a retail store.

One Naming, Two Forms

Technical framing

Every named entity and operation in the format is identified by a category and a member: category.subtype for entities that exist, category.verb for operations that fire. The form follows the role. A touchpoint is declared as a block; an action is invoked as a call. The grammar makes the distinction visible to anyone reading a file. A category MAY additionally declare category-level operations in the specification catalogue (category.verb, e.g. actor.cue); a declared operation is valid in type position beside the category's subtypes — the catalogue declaration, not the word's grammatical class, is what admits it there.

When a designer writes actor.host, they are naming a thing — a host who participates in the journey, declared once and referenced by other constructs. When they write cue(), record(), or merge(), they are firing an operation — a runtime event with arguments and a return point. The block-versus-call distinction is not decorative. It mirrors the underlying semantics: entities are stable across a state's lifetime; operations are momentary, ordered, and traceable.

Rationale

This duality keeps the format legible at scale. A reader scanning a journey can distinguish "what exists" from "what happens" at a glance, without consulting the spec to decide whether cue is a touchpoint or an action. The naming rule and the parser cooperate: the parser rejects any form in a position the catalogue does not declare for it, so undeclared misuse fails early rather than producing surprising runtime behaviour.

One Catalogue, Many Domains

Technical framing

The format has one catalogue of categories and subtypes. There are no aliases, no domain dialects, no parallel namespaces. A clinical pathway, an immersive activation, and a learning experience all reach into the same vocabulary; they differ in which subtypes they emphasise, not in which language they speak.

Vocabulary packs extend the catalogue with domain-specific subtypes within the existing category structure. A medical pack adds actor.clinician under the same actor category that already houses actor.host and actor.guide. A retail pack adds wearable.watch.smart.acme under the same wearable.watch.smart family. New subtypes nest under existing categories; they do not invent new top-level vocabularies that compete with the base.

Deliberate limits

  • P406.synonym
    • Limit: a second name for something the catalogue already names: a house term, a brand's word or a domain dialect used as a type, an action, a condition or an event, in place of the catalogue's own name for the same kind. ("We call them cast members, and the file must say so.")
    • Not this: a type or an action that a vocabulary pack the file imports with use declares for a kind the catalogue does not already name; the author's own names for each touchpoint, state and moment; the author's term written in the file's intent.
    • Instead: in-file: the instance is named in the author's own words and typed from the one catalogue. The author's term also lives in intent:.
    • Attempted in: touchpoint type; action name; guard expression; event match.
    • Message to the author: "You name your own people, places and moments however you like. The kind of thing each one is comes from one shared catalogue and the packs the file imports, so every venue and every tool reads it the same way."

Rationale

This is the rationale that animates the catalogue naming convention. If two domains were free to fork the catalogue, the language would fragment into mutually unintelligible dialects within a year of release. By forcing every subtype into the same compositional shape — and by validating that shape at pack registration — the format stays one language across every domain that adopts it. Authors learn the catalogue once. Tools index it once. Cross-domain experiences (a museum that hosts a learning programme and a retail flagship) compose without translation layers.

Vocabulary packs are files: on disk under vocab/ (cross-experience scope) or carried inside the .xp bundle under vocab/ (experience-local scope). Both flow through the same registration pipeline; both honour R112 and R116. An experience file never declares vocabulary inline.

No subtyping, leaf-typed. The format declares no subtype relation. Every type is its own primitive; relationships between types are advisory metadata, never substitutability. portability.realm documents which realms can flow content into which others — it describes flow direction, not partial order, and a value declared realm: virtual is never substitutable for realm: physical even if the portability matrix permits content flow between them. Type predicates evaluate by exact match against the catalogue. This forecloses an entire class of evolution traps: introducing subtyping additively in a future major release is permitted (R802-safe); declaring a partial order now and backtracking would re-classify existing programs (R802-breaking). The leaf-typed posture preserves the option without committing the cost. See RULES.md R807 + R808 for stability tier mechanics; see Principle P701 (Warn-but-Preserve for Forward Compatibility) for handling of unknown metadata keys.

One declaration, derived projections. P406's "one catalogue" discipline extends to the narrative structure: there is one declaration of each journey beat, in exactly one place in the journey { phase ⊃ moment ⊃ state } tree. No parallel enumeration — no journey.map alongside the journey, no group re-listing states already declared in the transition graph. Design-time views (arc diagrams, storyboards, visual journey maps) are projections computed from the single canonical tree; they are generated by tooling, never retyped. This is the P406 "one catalogue" guarantee applied to authoring: the catalogue of beats is the journey hierarchy itself, not a separate arc-authoring surface that must be kept in sync. Cross-reference: P401 (single-declaration discipline), R134 (Single Journey Enumeration — governs the phase ⊃ moment ⊃ state hierarchy).

One Experience, Two Shapes

Technical framing

An experience travels in one of two shapes: the text alone, or a ZIP container holding that text together with the assets it names and every vocabulary pack it imports. Both are .xp. A reader decides which it has been handed by the bytes, never by the file name — the ZIP magic bytes identify an archive, and manifest.json at its root marks it as an experience container rather than an arbitrary ZIP — so the extension names the experience, not the packaging. A venue travels the same way (P410).

The container is an envelope, not a format. There is no container-only construct, no manifest field that overrides a declaration in the text, and no experience that behaves one way packaged and another way plain. Opening a container yields exactly what the standalone text would have given — plus the assets that text names and the packs it imports, and nothing else. The canonical form of an experience is always the human-readable text (P402); the container is how that text travels with what it references (P404).

A container may also carry evidence about its contents — readiness receipts (P109) — and tooling state that describes how the contents were viewed. Neither is experience content: neither is resolved when the container is opened, and neither may alter what the text declares. A reader that ignores them reads the same experience.

Because a reader must open a container before it reads a single word of the text, the envelope declares what lies inside: the manifest states the spec version its contents target, and a reader rejects any container that omits it (R3011). This is the discipline P504 demands of a runtime, applied at the package boundary — verify the declared version against what you embed, refuse what you cannot verify, never guess.

The two shapes flow through one pipeline. A reader handed plain text synthesises the same manifest in memory — one entry, computed checksum, current spec version — so there is no plain-text code path to drift from the packaged one. Plain text is valid input to every conforming tool. A publisher of a canonical artefact — a use-case template, a lens library, a production deployment — ships the container, so the artefact carries its assets, its checksums, and its declared version with it (R3013). Loose text is for what stays close to home: fixtures, documentation, working files.

Text that imports a vocabulary pack is not a complete artefact in loose form: the pack is its semantics and has nowhere to live outside a container. Such text remains valid parser input, and cannot be delivered or run.

text
welcome-gallery.xp ← one file to the file system; a container to a reader
├── mimetype ← first entry, uncompressed: application/vnd.openxp+zip
├── manifest.json ← spec version, entry point, per-file SHA-256
├── experience.xp ← the entry point the manifest names — unchanged by packaging
└── assets/
├── welcome.mp3
└── hero.png

The container's mechanics are specified in xp-format-1.0.md and the manifest schema xp-manifest-1.0.json.

Rationale

Containers grow semantics unless a principle forbids it. The pressure is constant and each instance is reasonable on its day: a manifest field that would save a parse, a default that applies only when bundled, a shorthand the packager understands and the parser does not. Each addition is small; together they make the envelope a second language wearing the first one's name, and every reader must then implement both. The mimetype-first convention is borrowed from EPUB and ODF deliberately — those formats prove a container can stay an envelope for decades, but only because their specifications say it must.

Declaring the version at the envelope costs one manifest field and removes the failure that is worst precisely when it matters most. A reader that parses a future version's text against today's grammar does not fail — it produces a confident, plausible, wrong result. An honest refusal at the manifest is cheaper than a plausible misreading at the parser.

Splitting the obligation between reader and publisher keeps both halves honest. If readers could demand containers, a fixture or a documentation snippet would need zipping to be read at all, and the format would stop being the approachable text P006 promises. If publishers could ship loose text as a finished artefact, a use-case would arrive without its assets, its checksums, or its declared version — the three promises the manifest exists to keep.

One Fact, One Authority

Technical framing

An experience file and a venue describe the same room from two different authorities. The experience file carries the designer's intent — the spatial requirements the experience states it needs: dimensions, capacity, the commitments it makes to every venue that will ever host it. The venue carries as-built reality — the geometry a survey measured, not the geometry a designer wished — in two documents with one line between them: the manifest defines the venue's space and its operational constraints, the stage defines the built fabric's shape; where they disagree the manifest's declaration decides and the disagreement is recorded, never resolved silently; the manifest never describes fabric. What is space and what is shape is defined once, in the principle that carries the venue out to other tools and home again (P411). Room shape never enters the experience file. The two are different assertions about the same room — a requirement and a measurement — and each has exactly one home: intent is authoritative in the experience file, reality is authoritative in the venue. Where a consumer needs the room as it is, deterministic venue data supersedes designer-stated requirements — the precedence is fixed, never a consumer's choice — and the stated requirement survives as what the venue is checked against.

The same boundary holds on the capability axis. What an experience requires of a touchpoint is a fact of the experience file — the capability it declares, and the events and commands its journeys, policies and actions use on it (P409) — and what the venue can actually provide is a fact of the venue: the connector bound to that touchpoint, and what that connector's descriptor states it provides, which is what the binding is checked against (R1003). The two are a requirement and a measurement of the same touchpoint, and they divide exactly as stated dimensions and surveyed geometry do: intent is authoritative in the experience file, reality is authoritative in the venue, and where they disagree the venue decides what can run while the stated requirement survives as what the venue is checked against. This holds whether a capability differs in kind or in degree — a resolution, a throw, a sample rate, a channel count: the degree an experience requires is the experience file's fact and the degree a venue has is the venue's, and neither is a fact of the other.

Within the venue, authority is singular too. The stage is part of the venue: it sits beside the manifest in the working copy, its content hash is recorded in the manifest (R1018), and it is copied inside the shipped container, which references nothing outside itself (P410). A venue with no built fabric carries an empty stage that still declares its units and up-axis. Each fact about the venue has one document that carries it; a document that declares two representations of one fact declares no fact at all — it states a conflict without a resolution, and leaves every consumer to invent its own answer.

The shape must survive the round trip. It leaves the venue to be worked on in the tools that survey, model and light real buildings — tools that owe this platform nothing — and it must return without platform-invented facts being silently shed (P411). What each tool preserves is not assumed but recorded: the round-trip suite records what survives a tool before that tool is listed as supported. A conversion that loses information silently is not an interchange but a second, poorer source — and re-importing it silently rewrites the fact it claimed to carry.

Deliberate limits

  • P408.as-built
    • Limit: a particular venue's real room or real equipment written into the experience file. This covers a surveyed floor plan, the measured shape and size of one room, or what one venue's equipment actually provides (its resolution, throw, sample rate or channel count).
    • Not this: a setting the touchpoint's type declares, holding what the show needs rather than what one venue has, such as a camera's resolution, fps or count; cataloguing facts in the file's meta block.
    • Instead: venue: the venue manifest and its stage carry the as-built room, and the descriptors of the bound connectors carry what the equipment provides. The experience file states the requirements it needs.
    • Attempted in: touchpoint configuration; experience-level block.
    • Message to the author: "Your file says what space and what equipment the show needs. The real room and the real equipment (the room's measured shape and size, and what each device can actually do) are described once, in the venue's own file, so the same show can play in many rooms."

Rationale

The split follows from what each document can know. A designer authoring an experience for venues not yet chosen cannot know any venue's as-built geometry; a venue survey cannot know what a future experience will require. One document declaring intent and another resolving it against reality is the platform's own architecture — control planes declare desired state, the data plane resolves it — written into the artefacts. Collapse the two and one of them lies: the experience stops being portable, or the venue stops being real.

Two authorities for one room is how a walkthrough validates in the studio and collides at the venue: the diagram draws the designer's rectangle while the guests walk the surveyor's polygon. Naming a single winner — reality, deterministically — turns that disagreement from a silent divergence into a resolvable merge, and the losing value is still preserved where it belongs, as the stated requirement the venue can be checked against. Inside the venue the same rule holds: the declaration decides, the disagreement is recorded, and the repair is a re-survey or a stage correction, never a silent override.

Interchange with the world's geometry formats is not optional — venues are surveyed, modelled and lit in tools that will never speak this platform's schemas, and USD is their lingua franca. What is optional is whether interchange erodes the original. Recording what each tool preserves, before the tool is relied on, makes erosion detectable by a gate instead of discoverable at a venue; a shape that cannot come home intact was never safe to send out.

Touchpoints Declare Capabilities; Connectors Speak Protocols

Public framing

A designer declares that an experience needs a camera, a cue, a light, a tap — never that it needs OSC on port 8000. Which driver carries the cue, which protocol that driver speaks, and which address it goes to, are facts about the venue, and they are written where venue facts live. An experience file declares only the capability it requires; a venue that can provide that capability, by whatever means it has, can host the experience unchanged.

Technical framing

A touchpoint type names a capability — what is sensed, output, controlled or synchronised — never the wire protocol, transport, product or vendor ecosystem that delivers it. The facts about delivery — a host address, a port, a message broker, a credential, a DMX universe and address, a device identifier, a table mapping messages to events — are facts about a particular venue (P408). They belong in that venue's manifest, in the entry that binds this touchpoint; they are not fields of the experience format (P001, P505). The experience file has no construct in which a protocol, an address or a product can be named, so it cannot say one even by accident.

A capability is complete on its own terms: every event and command a type declares must be interpretable definitively by any real endpoint that provides that capability, without deriving meaning from the experience file, the venue file, or documentation held elsewhere. What an experience uses on a touchpoint — the events its journeys, policies and safety envelope listen for, the commands its actions and fallbacks call — is its capability commitment for that touchpoint; no second declaration exists to drift from it, and a venue may host the experience only where it can provide that commitment in full.

Three tests decide what belongs in the catalogue:

  1. The touring test. If a value would change when the same experience tours to a different venue, it is a venue fact.
  2. The naming test. If a name describes how data travels, or which product or vendor carries it, rather than what a participant or environment does, senses or perceives, it is a transport or product binding, not a capability.
  3. The interpretability test. If an endpoint providing the capability could not act on an event or command without consulting another source, the vocabulary is not yet a capability.

A type or field that fails any of the three is a defect in the catalogue and resolves upward under P507.

Three files meet at this boundary, and each has one job (the five artefact types are set out in STANDARDS.md):

  1. The experience file, in the .xp format, is the designer's declaration of intent (P001).
  2. The venue manifest, a .xpvenue file governed by the deployment-wiring rules (R10xx), is the venue's declaration of as-built reality (P408): what hardware exists, and one binding for every touchpoint the experience declares. A binding names a connector — a driver the fabric supplies, shipped with the platform or installed as a connector package the fabric declares, that speaks one or more protocols and states which capabilities it can provide — together with that connector's settings and whether it is being simulated.
  3. The connector fabric is the platform layer between the runtime and the hardware, where the connectors themselves live. It is supplied to the runtime as a declaration — each connector described as data before anything is bound — so what a host can run is a fact the runtime reads, never one it assumes.

The runtime reads the experience for what is required, the venue manifest for what is bound, and the fabric for what can run.

The runtime conducts; a device plays its part through the fabric. A device is anything that shows output or takes input while an experience runs: a screen, a speaker, a light, a phone, a kiosk, an app that plays films. It takes part as a connector instance a venue binds, or as the host of one, and in no other way: it receives the commands the experience issues to its touchpoint, reports the events the catalogue gives its type, and does both through the fabric. It acts on those commands, on its touchpoint's declaration and on its type's catalogue entry, and carries out what they hand it: it counts a choice's declared timeout and reports expired, draws the option that stands selected under initial: random, and reports an asset's marks as playback passes them. What any of that does to the story is the runtime's to decide. The device, and the connector it speaks through, hold no story: no branch, guard, default, remembered choice or step the file does not state, and neither reads the file, or the runtime's parse of it, to decide what to send or when. A device never posts events through a runtime's event-ingestion or operator surface, which belongs to operators (P106) and to test harnesses: a product that does skips the venue's bindings, the connector's health and the commands the file issues, and has become a second engine. A host that carries a runtime inside it may tell its own device how the run stands (started, resumed, stopped, failed), may show where the story stands read-only, as a viewer does, and may resume a run by giving a fresh runtime the device's own recorded events unaltered; nothing it passes or replays outside the fabric changes what the runtime is told. Where a device needs something its commands do not carry, the catalogue or the file gains it (P110, P412); the device never supplies it.

The experience declares a cue surface and a proximity zone, and nothing about wires:

experience.xp
1touchpoints {
2 house_cues: control.cue {
3 intent: "Fire the lighting and sound cues that frame each act"
4 role: master
5 slot: "stage-left-desk"
6 }
7 foyer_zone: sensor.proximity {
8 intent: "Know when a ticket-holder has arrived in the foyer"
9 slot: "foyer-arch"
10 }
11}
12 
13journey "evening" {
14 initial: doors
15 terminal: [seated]
16 state doors {
17 on foyer_zone.enter -> seated {
18 do: mcp.call(connector: "#house_cues", args: { command: "go", cue: 1 })
19 }
20 }
21 state seated {}
22}

The venue manifest binds each touchpoint to a connector and carries every transport fact:

json
{
"bindings": {
"house_cues": {
"connector": "osc",
"settings": {
"host": "192.168.10.20",
"send_port": 53000,
"address_map": { "go": "/cue/{cue}/go" }
}
},
"foyer_zone": {
"connector": "ble",
"settings": { "uuid": "…", "enter_threshold": -70 }
}
}
}

A second venue binds house_cues to midi with an event_map and foyer_zone to a camera-based presence connector; the experience file is byte-identical at both. A venue that cannot provide go on a cue connector cannot bind house_cues at all, and says so before anything starts.

Neither block names a type the catalogue does not define, and no venue fact appears in the experience file. That is the whole principle, shown once.

Deliberate limits

  • P409.protocol
    • Limit: how a device is wired, reached or made: a protocol, a port, a network address, a DMX universe or channel, a credential such as an API key, a driver, or a product or vendor named as the thing that carries a capability in place of what it does (a named make of light or speaker).
    • Not this: naming a touchpoint the file declares and a command its connector declares, with the arguments that command declares; a token type the catalogue names, such as type: nfc.uid, type: email, type: qr, type: account or type: phone; the guest an output is addressed to; the slot a touchpoint names for the venue to bind. A device's address passed as an argument is never one of these.
    • Instead: venue: the venue's own file binds each touchpoint to a connector, and that binding holds the protocol, the address, the DMX universe and channels, the credential and the make of device.
    • Attempted in: touchpoint type; touchpoint configuration; action name; action argument.
    • Message to the author: "Your file says what the show needs: a light, a cue, a camera. How each one is wired and reached, and which make of device does the job, is written in each venue's own file, so the same file plays, unchanged, in any venue that can provide what it needs."

Rationale

This is P001, P002 and P408 applied to the boundary between the experience and the hardware, stated once so it cannot be re-derived differently. P002 places the unit of design at perception, "not a DMX channel, MIDI note, or API call"; P408 places reality in the venue manifest; P505 excludes configuration from the format. Without this boundary a category defines itself by its transport or its vendor, and the experience stops being portable exactly as P408 predicts: a venue that can fulfil the identical intent over a different wire cannot host it without editing the file.

Sensing that describes a participant's action names a capability because it describes what happens at the touchpoint, not how the result travels: a tap, a presence in a zone, a position. Synchronisation to an external clock is a capability; the wire format that carries the clock is not. Cueing an external show system is a capability; the show-control protocol that carries the cue is not. A vendor's hub is a connector; the light, climate or scene it controls is the capability.

Making the experience's own usage its declaration is what keeps the boundary honest in both directions. A declaration the file could write but never exercise is a promise no venue can be checked against; a capability the file exercises but never declared is a hole no gate can see. One source, read from the graph, removes both.

A device that decides any part of the story is a second engine: it drifts from the file, and two devices playing one file play two stories. Keeping every decision in the runtime is what lets any device that provides a capability play any file that needs it, unchanged, and what makes a gap a device meets surface where it can be fixed, rather than be drawn around at the end of the chain (P412).

One Venue, Two Shapes

Technical framing

A venue travels in one of two shapes. The plain shape is the manifest document with its stage — every layer the stage composes and every asset it references — and the assets the document names, beside it: the working form, in which one building's stage may sit beside several venue documents. The container is a ZIP archive holding the venue document at its root, under the name venue.json, together with that stage, its layers and referenced assets, the assets the document names, and the evidence about the venue: the shipped form. Both are .xpvenue; a reader decides by the bytes, never by the file name: the ZIP magic bytes identify an archive, and venue.json at the root marks a venue container, as manifest.json marks an experience container (P407). A stage's layers and assets are direct members of the archive, never a nested archive.

The container is an envelope, not a format. It carries no record of its own: the archive's directory lists the members, and the document is the sole authority for every fact about the venue — its identifier, its schema version, its fingerprint, the stage it names and that stage's content hash. No container-only construct, no member overrides the document, and no venue behaves one way packaged and another way plain: opening a container yields exactly what the plain shape would have given, and nothing else.

The stage — its entry layer, every layer it composes and every asset it references — is a set of members of the container, never a neighbour of it, and a venue with no built fabric still carries its empty stage. The container holds the stage's files as authored, byte for byte, never flattened or rewritten; the document records the stage's canonical content hash (R1018), taken over the composed stage, so that what is hashed is what is read. A container whose composed stage does not hash to the recorded value, or whose document names an entry layer the container does not hold, is invalid. No packaging or reading step recomputes or rewrites the recorded hash to make a container conform: a changed stage is a changed venue, reconciled only at the authored rung, and a shared building stage that changes re-fingerprints every venue that records it.

Evidence — readiness receipts, venue evidence records, audited exceptions (P109, R1051) — travels inside the container as members under one evidence directory. It is cargo, not content: it is not resolved when the container is opened, it cannot alter what the document declares, a reader that ignores it reads the same venue, and a container reader checks nothing about it — its validity is the audit's business. No evidence member legalises an invalid document or stage, excuses an unregistered stage element, or permits a rejected stage to be packaged. The venue fingerprint is a function of the document alone, in canonical form (R1036); adding, removing or replacing evidence changes no fingerprint, every hash of the document is over its canonical form, and unpacking and re-packing a container leaves every receipt keyed to it valid.

A deployment-mode experience container carries the venue as exactly one member, in container shape; the experience container's own venue-fingerprint field restates the fingerprint computed from that member's document and is invalid if it differs.

An audited exception is evidence, never a field of the document, and waives nothing about the document's schema or the stage's profile.

Rationale

The container is an envelope for the same reason the experience container is one (P407). An envelope that carries a fact of its own is a second document about the venue, and every reader must then reconcile two; naming the document as the sole authority, and letting no member and no container-only construct override it, keeps the shipped form and the working form the same venue. A reader that opens a container learns nothing the plain shape would have withheld, and nothing the plain shape would not have said.

The stage is content and evidence is cargo, and the two are treated differently on purpose. The stage is what a venue is made of, so it travels inside the container as authored, and its recorded hash is the check that what arrived is what was packaged; a tool that rewrote that hash to make a container conform would be certifying its own edit, and the fact the hash exists to protect would be gone. Evidence is what has been said about the venue, so it rides along unread by the container reader and leaves every fingerprint where it was: a receipt that moved a fingerprint would go stale by being added, and a receipt that could legalise a rejected stage would make the audit's verdict a matter of packaging.

A deployment carries the venue in container shape only because the plain shape is a working form: one building's stage may sit beside several venue documents there, and which document the stage belongs to is a fact the working copy knows and an archive does not. At the point where an artefact leaves the tree, the venue travels whole — its document, its stage and its evidence in one place — and the fingerprint the archive restates is computed from that one document, so the archive can be checked against what it carries and never trusted on its own word.

The Venue Travels, and Comes Home Intact

Technical framing

A venue's shape is written in USD, and only there. The tools that survey, model and light real buildings already speak it and do not speak this platform's schemas, so the shape leaves the venue to be worked on in those tools, and it must return without platform-invented facts being silently shed. Shape is the built fabric: meshes, terrain, fixture geometry, the optical parameters of a light. A venue with no built fabric carries an empty stage that still declares its units and up-axis (P408).

Everything the venue knows about its space stays in the manifest's own document: named zones with their polygons and kinds, rooms and their adjacency, apertures with their clear widths, the positions and poses of bound devices and displays, keep-clear regions, surfaces as bindings. Space is polygons, extents, poses and parametric constraint volumes, never meshes.

A fact belongs in the stage only if losing it can produce a wrong picture, and never a wrong decision. How a surface looks, and what colour a light casts, is a picture. Where the room's edge lies, and how wide a doorway must stay clear, is a decision. A picture can be redrawn once someone notices; a decision that quietly lost its input has already been taken.

Visual is not the same as picture — the stage carries a value whose loss can be redrawn; any limit on that value that decides safety or compliance (a flash-rate ceiling, a luminance bound, a contrast requirement, a keep-visible line of sight) is a typed constraint in the manifest. Every spatial boundary that decides an operational limit — a room's edge, an aperture's clear width, a keep-clear volume — is manifest space, never stage shape.

Two facts about the world put the line there, and either one alone would justify it: a tool chain that preserved everything would remove the first and leave the second standing.

The first is that the journey out passes through tools that owe this platform nothing. A commodity tool keeps what it understands — meshes, transforms, lights, materials — and discards the rest without a word. Anything the platform invented for itself comes home missing, and nothing reports it.

The second is that the two documents disagree about the unrecognised. The manifest rejects a field it does not know, so a mistake stops the venue from loading. A stage accepts one, so the same mistake becomes a value nobody set and every reader sees as absent. One fails safe. The other fails silently, and it fails in the direction of proceeding.

A leaf prim carries only the venue's immutable identifier as its name, and the stage carries no platform metadata or roles; each role is the manifest's, keyed by that identifier (R1054), and appearance rides in the stage's standard material bindings. The manifest declares the venue frame; the stage declares its units and up-axis. A named prim binds only when the stage places it within the tolerance the manifest declares for its pose; otherwise it does not bind, and the disagreement is recorded, never resolved silently (P408).

Rationale

The line is drawn by the two facts the framing states, and both are recorded because each fails on its own: a tool that discards what it does not understand loses a fact on the way out, and a stage that accepts what it does not recognise turns a mistake into an absence that no reader reports. A principle resting on the first alone would look solved on the day a tool chain preserved everything, and the second would still be standing. Recording both keeps the line where the decisions are — in the document that refuses what it does not know — however faithful the tools become.

Where a Fix Lives

Technical framing

Five tests decide where a fault is owned, and each is a gate at one stage of a venue's life: authoring, ingestion, execution, diagnosis and maintenance. Each test decides one class of question, and no two decide the same one, so the stage at which a fault presents names the test to apply.

At authoring, the test is whether losing a fact produces a wrong picture or a wrong decision. A fact belongs in the stage only if losing it can produce a wrong picture, and never a wrong decision (P411). Two legs hold the line there, and both are mandatory: the tools that survey, model and light real buildings drop platform-invented data silently, and the manifest fails closed on an unknown field while the stage fails open. Visual is not the same as picture — the stage carries a value whose loss can be redrawn; any limit on that value that decides safety or compliance (a flash-rate ceiling, a luminance bound, a contrast requirement, a keep-visible line of sight) is a typed constraint in the manifest.

At ingestion, the test is whether a fact was narrowed or lost silently. Narrowing is legitimate; silent loss is a defect. Narrowed means the consumer read the fact and represented it at lower fidelity, recorded; lost means the consumer never read it. Both halves of the adapter keep a consumed-paths record and report each top-most unread subtree as a finding in the build report.

At execution, the test is whether a refusal says "I cannot" or "you are wrong". A component may refuse only on its own inability — it cannot read, cannot resolve or cannot write — and never on a verdict about a document it did not author. An input the component could read is never a ground for withholding its artefact — it produces what it can, records every fact it could not consume in the artefact's own surface and in the diagnostics the receipt chain carries, and an artefact that would mislead is corrected by its surface saying so. Withholding is never the safety mechanism — the production start reads the receipt chain, not the artefact, and refuses under P107, so a defective build reaches a venue only by a recorded human waiver and never where the machine found the defect. This test governs artefact production; an act (a production start, a publish, a deploy, anything whose effect reaches outside the tree) is governed by its own gate; an inability refusal names in the record the path or field it could not read, resolve or write.

At diagnosis, the test is which single document one would edit to make a finding go away; the answer names the finding's owner and the surface it is reported on.

The answerThe finding belongs to
the venue manifestthe venue evidence record (.xpreceipts/venue-<fp>.json)
the experience fileexperience diagnostics at its readiness rung
neither alone — only the two togetherthe pairing, at the bound / simulated rung
the renderer itselfthe build report beside the artefact
nothing; it is live statethe viewer, on its own surface

Two corollaries follow. A fact only a build could notice is not a venue fact, so the venue record keeps its single producer: a venue fact is establishable from the venue alone, and a fact that needs an experience in hand to see was never a venue finding but a pairing finding or a build fact. An invariant breach is owned at source, what the compiler did belongs to the build report — even when the reason names another document. The document to edit is the one whose statement is false; where each document is true alone and only their combination fails, the finding is the pairing's. A document not in the table owns its own findings on its own surface, and the table grows only by ruling.

At maintenance, the test is whether the renderer is wrong. When an anomaly presents in the render or on the viewer, the renderer is at fault in exactly two ways — it failed to read and render a .xp or .xpvenue faithfully, within the numeric budgets it publishes per target, and where it publishes none a performance finding is its own; or its surface misleads, meaning a state it is in (inert, evidence absent, a zone unreachable, a legitimate absence) is not shown or is shown as a fault. Everything else in the render belongs to the seam that owns it. The renderer gains capability when the specification it consumes changes, and never changes to compensate for another document's defect. A backend that receives a correct scene document owns its own failure to render it.

Rationale

The five tests are gates at different stages so that no two compete for one finding. A fault met at authoring asks which document carries a fact; met at ingestion, whether a consumer kept it; met at execution, whether a component may withhold what it made; met at diagnosis, which document is false; met at maintenance, whether the renderer is the seam at fault. Each question has one test, and the stage names the test, so an owner is found by asking one question rather than by arguing over five.

The tests exist because the end of a chain is the cheapest place in a platform to hide a defect found anywhere along it. A renderer can draw around a missing fact, a caller can post what a connector failed to send, a build can refuse rather than report — and each makes a symptom disappear while the defect stays, so that the next consumer meets it with no record that it was already found. Fixing the seam that is broken, never routing around it, needs a way to name the seam that does not depend on who is asked; the tests are that way, written down.

Governance and Evolution

Immutable Released Versions

Technical framing

Once a spec version is released (e.g., openxp/1.0), it is frozen. No fields are added, removed, or changed. All evolution happens in the next version. The spec.hash in every experience file header creates a tamper-evident link between the file and the spec version it was authored against.

experience.xp
1experience "Versioned" {
2 intent: "Pin the authoring-time spec so drift is detectable at load"
3 spec: "openxp/1.0"
4 spec.hash: "a1b2c3d4e5f6" // SHA-256 prefix of the spec at authoring time
5 version: "1.0"
6}

Rationale

Mutable specs create a class of bugs where the same file parses differently depending on when you downloaded the spec. Immutable versions guarantee that a file that parses today will parse identically in ten years.

Additive Within Major, Breaking at Major

Technical framing

Within a major version (1.x), changes are strictly additive: new touchpoint types, new actions, new keywords. No existing construct is removed or changed in meaning, with one exception that only the author can opt into: a name at the experimental tier may be removed in a minor version, and a file that uses one declares it. An addition can still take a name the author invented, or a name a vocabulary pack the file imports defines, and that pack is then refused until it is updated; from the version that admits community/ or third-party/ packs, the pack is no longer refused for that clash, and a bare use of the shared name is refused until it is qualified (R802). Breaking changes — removal of types, changed semantics, restructured blocks — require a new major version (2.0).

text
1.0 → 1.1: Add perception.temperature type ✓ Additive
1.1 → 1.2: Add "retention" keyword ✓ Additive
1.2 → 2.0: Remove "extend" block, replace with ✓ Breaking (new major)
"vocabulary" block

Rationale

Additive evolution means that nothing a valid 1.0 file uses is removed or changes meaning in any 1.x version, except an experimental name the file declares, and except through an addition that takes a name the author or an imported pack invented. The author adopts new features at their own pace. Parsers can be forward-compatible within a major version. An addition can still take a name the author invented; the words reserved ahead of use prevent this for the additions they name, and for no others. Library versioning accepts the same risk.

Self-Governing Evolution Loop

Public framing

OpenXP is designed to evolve openly, with proposals and human judgment working at different speeds. A proposal — a new touchpoint subtype, a new guard function, a new vocabulary pack — can come from a human contributor or from an AI agent; the loop does not care which hand drafted it. Either way it flows through the fixtures that validate it, the CI that propagates it across the platform, and the human gate that approves every normative change. The platform's own governance is itself an experience file — a journey of states and transitions the runtime executes. This is not a theoretical curiosity. It is the operational shape of how OpenXP gets better without losing the discipline that makes it trustworthy: AI speed paired with human approval, automated validation paired with manual review, continuous evolution paired with immutable releases.

Technical framing

The spec, fixtures, sync tooling, and CI drift checks form the foundation for a self-governing evolution loop: a change is proposed — by a human or by an AI agent — fixtures validate it, CI propagates it, and a human approves every normative change. The loop is governed by policies declared in the format (Principle P403) and protected by immutable versioning (Principle P501).

text
Change proposed (human or AI agent)
→ fixtures/ validate it (parser conformance)
→ CI propagates it (sync-spec.sh + drift check)
→ Human approves it (policy: human_gate)
→ Version bumps
→ All modules sync

Rationale

A language that evolves only through human committee meetings evolves slowly. A language that evolves only through AI proposals evolves dangerously. The self-governing loop combines AI speed with human judgment, automated validation with manual review, continuous evolution with immutable releases.

Embedded Spec

Technical framing

Every runtime embeds its spec version at compile time. The runtime does not download, fetch, or discover its spec at startup. This guarantees that the runtime's behaviour is fully determined by its build, not by external state.

rust
// The spec is literally compiled into the binary
const SPEC: &str = include_str!("specs/xp-spec-1.0.json");
experience.xp
1// At parse time, the runtime verifies the file's spec.hash
2// against the embedded spec. Mismatch = warning.
3experience "Verified" {
4 spec: "openxp/1.0"
5 spec.hash: "a1b2c3d4e5f6"
6}

Rationale

External spec resolution introduces network dependencies, version confusion, and a class of "works on my machine" bugs. Embedding the spec makes the runtime self-contained: if you have the binary and the experience file, you have everything needed to execute the experience. No internet required. No configuration drift possible.

Experience Format Scope Integrity

Technical framing

The format's domain is experience execution. Its vocabulary — touchpoints, states, journeys, agents, policies, actions — forms a structural graph that the runtime traverses when executing an experience. Every construct in the format spec must participate in this graph: it must be reachable from, referenced by, or capable of affecting a touchpoint, state, or journey.

Authoring-time tools, creative thinking aids, design-phase annotations, and configuration formats that share no structural elements with the experience execution graph are not format constructs. Expressing them in the format syntax, extending the spec with their keywords, or including them in .xp files does not make them part of the format — it makes the spec incoherent.

The litmus test is direct: Can this construct appear inside an experience { } block and be meaningfully referenced by or participate in a journey — as something the runtime executes, or as a declared commitment the file carries per scope for the people and tools that read it (P001, P109)? If the answer is no, it must not extend the format spec.

One surface is declared rather than tested: the meta block (R105) carries author and tool metadata — flat typed key-value pairs preserved verbatim through parse and emit and never interpreted by the runtime. It is an inert, preserved surface, not an execution construct; it extends no execution vocabulary, and declaring behaviour in it has no effect. The carve-out is singular and closed: meta is the one declared home for cataloguing metadata, it grants no precedent, and the litmus test continues to bind every other proposed construct.

meta records facts about the file as a catalogued artefact — who made it, for whom, under what concept and how it is indexed — and nothing the tree declares or can declare with an existing construct (P408). A value that names a construct the file declares, or states what an existing construct states, is not metadata and belongs in the tree; a summary the tools can derive from the tree is derived, never declared. In the tree, every value is checked at validation: a reference is resolved to the construct it names, and an unresolved reference is an error; a choice is checked against the list that defines it, in the specification or an imported pack; a typed value against its type. Free text is checked only as text, and never stands in for a reference or a choice (P110).

This principle exists in productive tension with Principle P403 (Self-Describing). Self-description means that the platform's own evolution process can be expressed as an experience — with touchpoints, states, and journeys the runtime can execute. It does not mean that every tool the platform uses becomes format vocabulary. The self-describing property applies to processes that fit the execution model, not to every artefact in the platform's ecosystem.

Deliberate limits

  • P505.outside-the-experience
    • Limit: material about making the experience rather than about the experience itself: brainstorms, design notes and reminders, the settings of the tool that wrote the file, and configuration for other systems. It also keeps out a second listing of the journey's moments, such as a storyboard or a visual arc diagram, which tools draw from the one journey. [a journey.map]
    • Not this: the author's reasons for each part, written in the file's intent; the art direction's provenance, its freeze record of where its treatment was resolved from; cataloguing facts in the meta block.
    • Instead: authoring-tool: the authoring tool's own records, kept beside the file.
    • Attempted in: experience-level block.
    • Message to the author: "An experience file describes the experience. Brainstorms, notes, tool settings and storyboards sit beside it, not inside it; a storyboard is drawn from the journey, never written twice."
  • P505.catalogue-metadata
    • Limit: a fact about the file (who made it, for whom, what kind of show it is) carried as behaviour or as a block of its own.
    • Not this: the experience's own domain and modality fields, which the format defines; the file's own meta block, where these facts belong.
    • Instead: in-file: the file's own meta block, which holds flat cataloguing facts, kept exactly as written and never read by the running show.
    • Attempted in: experience-level block.
    • Message to the author: "Who made this, for whom and what kind of show it is can be written in the file's meta block; nothing there changes what the show does."

Rationale

A spec that absorbs the vocabulary of every adjacent tool loses its identity. The format's execution model guarantees — determinism, safety, policy enforcement, source mapping — derive from its bounded scope. When non-executable constructs enter the spec, those guarantees become undefined at their boundaries. A spec-compliant parser given an unknown block name must produce an error (R105). Allowing authoring tools to extend the spec either forces the runtime to silently ignore those blocks or forces every parser implementer to distinguish "real" runtime blocks from "merely" authoring-time blocks. That distinction has no place in a spec document.

Bounded by Structure, Not by Magnitude

Technical framing

The language guarantees that every evaluation is finite — and it does so structurally, never by fixing a magnitude. Iteration exists only over sets whose bound the author declares or the spec defaults (size.max); deadlines exist only where the author declares them (latency.sla); the property space is finite because every property is written out in the file. The declared bound is the mechanism; no number in the language stands between an author and a legitimate design.

Where a number does appear in the specification tree, it is one of three things, each carrying a machine-readable classification (R904): a value forced by an encoding or a cited external standard (encoding.forced); a conformance floor — "a conformant implementation MUST support at least N" — which binds implementations and is the portability guarantee (support.floor); or a documented implementation cap with a defined error code, which belongs to an implementation, never to the language (implementation.limit). A file within the floors behaves identically on every conformant implementation. An implementation that cannot honour a declared bound rejects the file loudly with its documented diagnostic — truncation, clamping, and partial evaluation are forbidden.

The test for any proposed number is inherited from the strictest precedent available: does the value fall out of the encoding, or is it a guess about what is reasonable? Guesses do not enter the language. Capacity opinions — how many participants, how large a venue — are domain declarations owned by the experience and venue files.

Rationale

Surveyed total and terminating languages state their boundedness guarantee structurally and fix no magnitude binding an authored source text in the specification; where numbers exist they are implementation floors, per-run declared bounds, or implementation caps kept out of the standard. The pattern holds because a magnitude in a language spec is wrong in both directions at once: too low, and it forbids authors legitimate designs while inviting an unanswerable "why not one more?"; too high, and it promises nothing an implementation can rely on. A floor has neither failure mode — raising it costs implementers only, and every file under it is portable everywhere. Fixing the number's role rather than the number itself also makes limits auditable: a classified number can be checked against its justification mechanically, while a bare number in prose drifts into consumer code and hardens into policy nobody chose.

Manifesto Supremacy

Public framing

This manifesto is where OpenXP's intent lives, and everything else — the specification, the rules, the schemas, the code, the CI — was built from it and answers to it. When the manifesto changes, the platform is reviewed against the change. When any other document is added, changed, or deleted, it is checked against the manifesto before the change lands. Where an artefact disagrees with a principle, the artefact is the defect — however established, whoever wrote it. And when the manifesto itself must move, that is a decision the platform owner takes deliberately — never a side effect of other work, never an inference from what the code happens to do. A contributor never has to guess which of two documents wins. The manifesto does, and the escalation path is written down.

Technical framing

The manifesto governs the entire OpenXP platform. The experience format is its first concern, but its authority does not stop at the language: the codebase, the specification, the rules, the governance documents, the standards, and the CI that gates them all exist in service of these principles and are measured against them. Precedence runs manifesto → rules → machine encodings → implementations → fixtures and documentation, and a conflict between any two layers resolves upward, never downward. This principle is complete in itself: nothing below this document defines any part of its meaning. Enforcement is delegated downward, as all enforcement is — R905 (Manifesto Change Review) binds the gates and the platform owner's approval to every change here, serving this principle exactly as every rule serves the principle it traces to.

Three obligations keep the hierarchy live rather than declared:

A change to the manifesto triggers a review of the platform. A changed principle silently re-classifies every artefact built on the old reading, so the change does not land alone: the platform — codebase, specification, rules, governance, standards, CI — is reviewed against the new text, and rules, governance, and standards are created or updated until nothing contradicts it.

A change to any other document is validated against the manifesto first. A document added, updated, or deleted — a rule, a schema, a standard, a workflow, a guide — is checked against the principles before it lands, not after it has been built upon.

Disagreement blocks, or escalates — there is no third path. Where the manifesto disagrees with a proposed change, the change is blocked, or the manifesto must itself be amended — and amending it is an immediate, unequivocal escalation to the platform owner. No document routes around a principle, and no principle is changed as a side effect.

The gates mechanise the structural half of this: every rule traces to a principle it names correctly, every principle is implemented by at least one rule, the supremacy statements stay intact, and the worked examples stay executable. Whether an artefact honours a principle's meaning is not decidable by a script. Reading the principle discharges that residue — prose binds where gates cannot compute.

Rationale

Without a single root, requirements accumulate wherever their writer happened to be standing: a rule citing a workflow document, a doctrine living in a contributor guide, a normative claim in an architecture note that no gate reads. Each placement is reasonable on its day; together they fragment authority until two documents disagree and nothing says which wins. A governance defect of that shape should never wait to be discovered — not by an audit, still less by a failure, the most expensive discovery of all. Conformance belongs at the source: a change validated against the manifesto before it lands never needs finding afterwards.

The review trigger exists because a principle change is never local. The platform was built from this document; changing a sentence here changes what counts as a defect everywhere downstream. Reviewing the platform at the moment of change propagates the decision deliberately. Skipping the review propagates it anyway — later, silently, discovered one contradiction at a time.

Deletion is validated for the same reason addition is. Removing the rule that implements a principle un-implements the principle, and doing so quietly is the easiest route around a constraint — which is why a principle left with no rule tracing to it fails the gate rather than fading out.

The escalation clause is what keeps supremacy honest in both directions. A manifesto that cannot be changed becomes a dead letter routed around by increasingly creative readings; a manifesto changed casually is not a source of truth but a mirror of the code. Requiring the platform owner's deliberate decision — for amendment, and only for amendment — makes the manifesto hard to move and impossible to ignore, which is precisely the combination a single source of truth requires. This matters most when contribution outgrows the founding team: the hierarchy a community inherits must be written where the community reads.

Machines Propose, Humans Decide

Public framing

OpenXP's code may come from a human hand or a machine one — AI agents may draft, gates verify every change, pipelines carry releases. No machine decides. Every decision that binds the platform — what a principle means, what conformance requires, what ships, what is overridden — is taken by a human being. The platform owner is a human, always, and explicitly never a machine. A gate saying no is a human's earlier decision executing; a machine saying yes is never, by itself, permission. This is the law the runtime already lives by — agents propose, policies constrain, operators override — applied to the platform that makes the rules. Wherever automation grows, the loop closes through a person.

Technical framing

The platform owner is a human being — always, and explicitly never a machine, an AI agent, or a quorum of them. The decisions this manifesto reserves are taken by humans and cannot be delegated to automation: amending the manifesto (P507); changing what conformance means — the rules, the grammar, the schemas; authorising a release or a seal (P501) — the machine turns the key, only a human orders the turn; resolving a governance escalation (P507); granting or revoking trust — a conformance certification, a signing key, a steward's appointment; and overriding a gate.

A change is normative when it changes what conforms. A formatting pass, a dependency bump, a regenerated projection that leaves conformance untouched needs gates, not ratification — the reservation binds meaning, not motion.

Machines may participate everywhere else: AI agents draft and propose, gates verify and block, pipelines build and publish. Participation is an option, never an obligation — a human writing every line is equally conformant. The line is authority, not activity, and the asymmetry is deliberate: a machine may always say no — a failed invariant blocks at machine speed, fail-closed — but it may never say yes to a normative change, and it may never forgive its own no. A gate that blocks a change enforces a decision a human already took, encoded as a rule; it exercises no judgement of its own. An escape hatch is a human's hand, or it is a hole. And the human's half must be real: an approval given without reading is a machine approval wearing a human name. A proposal from the platform owner is measured against the manifesto exactly as any other, and a contradiction is named to the owner before it is approved.

This is one law stated at every altitude. At runtime, agents propose and policies constrain; the operator's intervention outranks every agent tier (P103, P106), and the actor's in-the-moment judgement outranks the machine's (P005). At authoring time, the tool suggests and the author decides (P702). At governance time, automation prepares, validates, and propagates, and a human approves every normative change — the evolution loop (P503) is self-governing in exactly this sense: the platform's own declared policies validate proposals mechanically, and the approvals inside the loop are human.

Rationale

Authority follows accountability, and accountability cannot rest on something that cannot bear it. A human owner can answer for the platform's direction — to a community, a venue, a regulator, a guest who was harmed; a machine can answer for nothing. Reserving the deliberate decisions to the party who can be held responsible for them is not caution about what machines can do — it is precision about what responsibility is.

The deeper failure the reservation prevents is circular authority. Rule One's corollary holds that an implementation's behaviour is never evidence of what a principle means; the strongest form of that failure is automation quietly amending the principle to match the behaviour — a system approving its own homework, converging on whatever the system finds easy. A human decision at the boundary is the anchor that keeps the loop honest: proposals can come from anywhere at machine speed, but nothing becomes normative until a person, outside the automation, chooses it.

The cost is deliberate. A human in the loop is slower than automation, and at the moments this principle governs — an amendment, a seal, an override — slower is the feature: those are precisely the decisions that should not happen at machine speed. And the principle binds the kind of holder, not the number: how ownership is held among humans, delegated, or succeeded is governance mechanics (GOVERNANCE.md); that it is held by humans is constitutional, and does not change with scale.

Inheritance

Container Inheritance for Declarations

Technical framing

Block-scoped declarations — realm, senses, processing, intent, and other context-defining properties — inherit from the enclosing block unless explicitly overridden. A state inside a journey inherits the journey's realm and processing mode; a transition inside a state inherits the state's realm. Exiting an inner block restores the outer block's declaration; a child's override does not leak upward.

Container inheritance is type-correct: each field's merge behaviour matches its semantic type. For fields whose semantic type is one-of-many enum — realm (physical / digital / augmented / virtual), processing.mode (transient / scoped / retained), intent — inheritance applies replace semantics: the innermost declaration wins and the outer value is not consulted further. For fields whose semantic type is many-coexisting envelope — senses (sight + sound + touch can all be present simultaneously) — inheritance applies additive merge: child fields union with parent fields in declaration order, without duplicates.

experience.xp
1experience "Multi-Sense" {
2 intent: "Layer an additional tactile channel onto the experience-wide senses in one quiet zone"
3 senses: [sight, sound]
4 
5 touchpoints {
6 marshal: control.cue { }
7 }
8 
9 journey "tour" {
10 intent: "A tour whose quiet zone adds a tactile channel"
11 initial: quiet_zone
12 terminal: [atrium] // the quiet zone is a beat within the tour, not its end
13 
14 state quiet_zone {
15 senses: [touch]
16 // Effective senses at this state: [sight, sound, touch]
17 on marshal.fired -> atrium { }
18 }
19 
20 state atrium {
21 // back to the experience-wide senses, and where the tour is over
22 }
23 }
24}

Per-field merge mode is declared in xp-spec-1.0.json inheritable: blocks (merge: replace | additive). Sense Suppression — removing a specific inherited sense within a scoped block (e.g. senses { !sight } for a "dark zone inside a sighted realm") — is deferred to v2.x; v1.0 supports additive merge only.

The scenography block (the immutable art-direction blueprint) also joins this inheritable block set, declarable at experience/journey/phase/state. Its inheritable: declares merge: replace-per-axis — each of its eight axes (visual, light, sound, motion, materiality, scent, thermal, air) inherits independently and an inner block's axis supersedes the enclosing axis wholesale, never merging. This is the replace semantics applied at axis granularity, consistent with the realm/senses/processing replacement model above and with R209's unified inheritance walker. The principle-level treatment of the scenography blueprint is Principle P008 (Art Direction Is First-Class).

Rationale

Inheritance reduces repetition without hiding intent. A predominantly-physical experience declares realm: physical once at the experience level; only the scenes that step into augmented or virtual restate it. A reader scanning the file can rely on the rule mechanically — find the nearest enclosing declaration walking outward — without needing to track an accumulated state of merged values. The verifier resolves declarations the same way the human reader does, which keeps tooling and intuition aligned. Cross-reference: R209 (Container Inheritance Resolution).

Validation Discipline

Warn-but-Preserve for Forward Compatibility

Technical framing

experience files outlive the runtimes that first author them. A retail brand publishing an experience pack today expects every venue to play it tomorrow — including venues running last year's runtime, and venues that will update next year. Warn-but-Preserve is the rule that makes this work: when an older runtime encounters something in a file it does not recognise, it tells the operator about it and keeps the unfamiliar content intact. It does not crash and refuse the file. It does not silently delete what it did not understand. The unknown content survives, flagged, until a runtime that recognises it picks up the file.

The formal contract: when a validator or parser meets a key it does not recognise on a metadata field, it MUST emit a diagnostic warning that names the key and the spec version known to the runtime, AND it MUST preserve the unknown key intact through any round-trip. The unknown key is not silently dropped, not promoted to an error, and not mutated. This applies to metadata surfaces — compatibility.realm and the capture { } / deliver { } / schema { } block bodies (R125, R126, R127), and any additive metadata block introduced under R802. It does not apply to structural surfaces — touchpoint categories, journey/state/transition block shapes, action names — which remain hard errors under R105 (reject unknown top-level blocks) and R702 (catalogue uniqueness).

experience.xp
1// Future spec adds `compatibility.realm.bidirectional` metadata key:
2compatibility.realm {
3 physical → digital
4 digital → physical
5 physical ↔ augmented: { bidirectional: true } // ← new key in 1.2
6}

A v1.0 runtime parsing this file warns: "unknown compatibility.realm metadata key bidirectional on edge physical ↔ augmented (runtime knows spec 1.0; key may be defined in a later minor)" — and round-trips the value through emit unchanged. A v1.2 runtime accepts the key without warning. No code path branches on spec version; the warn-and-preserve behaviour is uniform.

Rationale

Warn-but-Preserve trades a verbose log line for forward-compatibility insurance. The trade is heavily worth it: the verbose log is fixable by updating the runtime; the lost data is not. Putting the principle at the language level — not in deployment review, not in a separate compatibility layer — means every runtime, validator, and tool that parses an experience file inherits the contract automatically. Forward compatibility is not a feature opt-in; it is the language's default posture.

Author Authority

Technical framing

The format validator enforces document structure and safety floors. It cannot inspect venue affordances, physical workarounds, staging bridges, or designer intent about physical reality. When a validation check touches the boundary between document structure — decidable from the format text and spec vocabulary alone — and the author's claim about physical reality — which requires venue knowledge the validator cannot have — the check is advisory. It informs the author but does not reject the document.

The validator hard-fails on two categories: safety violations (non-negotiable overrides of author intent due to legal liability or potential runtime harm) and structural well-formedness (the document is not valid experience-file text; downstream consumers cannot trust it). The validator warns on a third category: author-authority plausibility mismatches (the validator infers an inconsistency, but the author may have venue knowledge that resolves it). This three-bucket distinction is the organising axis for posture assignment across all L0-validate rules, formalised by R903.

Three-bucket posture assignment:

  • Safety and operational floor → ERROR. Non-negotiable; overrides author intent. Runtime-crashing or legally liable violations — photosensitive content warnings (R227), event-bus storm limits, recursion guards. The validator is the last mechanical defence before physical or legal harm.
  • Structural well-formedness → ERROR. The document is not valid experience-file text. Grammar violations, missing required fields, naming/format errors, namespace resolution failures, referential integrity breaks, closed-vocabulary membership checks, uniqueness and cardinality constraints. Downstream consumers assume these pass.
  • Author authority and plausibility → WARN. The validator cannot see venue affordances, undeclared physical passages, staging bridges, or the designer's representation of their physical installation. A realm mismatch between spec table and declared touchpoint, or a spatial reachability gap in the modelled topology, is advisory. The validator informs; it does not gatekeep venue knowledge.

Rationale

This principle grounds the platform's validation posture: safety and operational floors are errors, structural well-formedness is an error, and author domain intent warns — the three buckets R903 formalises, with the safety tier's precedence fixed by P103. The validator's authority stops precisely where the author's domain knowledge begins. A lighting designer declaring a DMX fixture as realm: virtual knows whether their installation uses a DMX-to-simulation bridge. A spatial designer declaring a zone transition the topology graph does not model may know of a physical passage not yet captured in the format environment block. Erroring on these cases would make the validator an obstacle rather than an assistant.

The canonical author-authority case is R604 realm-compatibility: virtual subsumes all touchpoint types (anything can be virtualised), and physically "impossible" effects are routinely achievable via undeclared affordances — trap doors, hidden panels, quick-change rigs, bridge adapters. The validator informs the author of the discrepancy; the author decides whether to suppress it (via suppress: [R604] on the touchpoint), update the format to match reality, or leave the advisory unresolved. Three outcomes, all legitimate. None require the validator to veto.

P702 and P701 (Warn-but-Preserve) form the two-pillar posture discipline for this section: P701 governs forward-compatibility — unknown future content is preserved rather than rejected; P702 governs author authority — venue-knowledge mismatches are advised rather than blocked.

Public framing

The format's validator is a structural referee, not a venue inspector. It hard-fails on broken documents and safety violations. It advises on physical plausibility — because the author knows their venue; the validator does not.

Origin & narrative voice

I love this industry. The people are extraordinary. The ambition is often audacious. But there is a technical challenge at the heart of everything we do:

We design for what people should feel, and then we build experiences with tools that only speak in what machines should do.

Somewhere between the original creative vision and the technical delivery, the human intent often gets watered down, or lost. The deeper the experience, the higher the risk — more systems, more vendors, more integration, more points of failure, and more cost. Often invisible until you are on-site at 3am asking “…whose responsibility is that?” — if the idea even made it that far to begin with.

The industry needs a common experience design language that starts with human perception, not hardware protocols.

Foundations that raise the floor, and the ceiling, so that everyone — from the kid in their bedroom to the team delivering something no one has ever built, in a place they have never been, to a deadline they did not set — is building on solid ground. A language that is open, accessible, and belongs to the industry, not locked into one vendor’s ecosystem.