MD

Runtime Authoring Guide

guides/runtime-authoring-guide.md

Runtime Authoring Guide

This guide is everything needed to build an Elonn Runtime: the component that presents Elonn to a member on a particular kind of device. It applies to every Runtime.

The guide is self-contained for authoring. Nothing a Runtime needs in order to present Elonn correctly depends on reading another document. The appendix lists the sources this guide is derived from.

The Runtime role

A Runtime is the architectural component responsible for member interaction and presentation. It is the member's interface to the platform.

A Runtime SHALL:

A Runtime SHALL NOT:

The Runtime owns presentation. Canonical data says what something is and where it is. The Runtime decides how that appears on its device.

Every Runtime presents the same canonical Datasets with the same meaning. Two Runtimes may look different, but a member's world must be the same world on both.

Talking to the platform

Authentication

Authenticate Members through the API. The API establishes Member identity before a request enters the platform, issues signed access tokens, and exposes the authentication endpoints. The Runtime does not implement its own authentication or session logic.

Calls to World

Following authentication, every request for the member's world goes to World. World is the only platform endpoint a Runtime calls for content. The Runtime never calls Conductor, a Service, or a Model directly.

A Call is a POST to the World call endpoint, {world base URL}/world/call. The base URLs come from the Runtime's configuration. A Call has three parts:

{
  "id": "call:runtime:<runtime id>:<unique timestamp or counter>",
  "content": {
    "operation": "world.compose",
    "input": { "type": "text", "text": "parks" },
    "operation_invocation": { "service": "...", "operation": "...", "arguments": { } }
  },
  "context": {
    "runtime": {
      "id": "<runtime id>",
      "version": "<runtime version>",
      "renderer": "<phone | headset | web | ...>",
      "capabilities": { "field_markers": true, "pointer_input": true }
    },
    "runtime_state": { "origin_object": "<object id, when the interaction is inside an open Object>" }
  }
}

- id is unique for every Call.
- content.operation names the World operation to run (see the table below).
- content.input carries member-typed text for search. Omit it when there is none.
- content.operation_invocation is present only when the member activates an Action. It is the Action's own operation_invocation, passed through unchanged.
- context.runtime_state.origin_object names the Object an operation applies to. Its meaning depends on the operation:
- For ordinary interaction inside an open Object, it is the container the interaction happened in. Supply it verbatim from the presentation the interaction came from. Do not derive it from your own view tree, and do not decide from the Object's type whether to send it. World decides what it means. Omit it to open a result as a new Object (alt focus, below).
- For world.focus, it is the Finding's Object, the Object World should open on Carry.
- For world.focus_region, world.back, and world.close, it is the open Object to act on.
- Each operation's table row says which applies.

Runtime capabilities

Declare in context.runtime.capabilities only what the Runtime actually presents. World composes its response from these declarations. For example, field_markers: true tells World that the Runtime renders Field placements. Declaring a capability you do not render makes World compose content you cannot show. Leaving a capability you do render undeclared makes World omit content you could have shown.

World operations a Runtime submits

| Operation | Purpose |
| --- | --- |
| world.compose | Search from Entry, with input. Adds Findings for new results. |
| world.restore | Rehydrate the member's world on launch or resume. |
| world.focus | Open a Finding's Object on Carry. Put its id in context.runtime_state.origin_object. |
| world.focus_region | Focus a semantic region of an open Object. |
| world.back | Step an open Object back one navigation state. Name the Object in origin_object. |
| world.close | Remove an Object from Carry. Name it in origin_object. |
| world.clear | Empty the Results pane. It removes Findings only. |

Each operation returns one Dataset.

Datasets

Every Call produces exactly one Dataset. A Dataset is immutable. When the world changes, World returns a new Dataset with its own id. Replace what you show with the newest Dataset. Do not patch a Dataset in place.

A Dataset is the only canonical response payload. Render from it, and from nothing else. Do not keep your own copies of navigation history, focus, or Findings. World owns them.

A World Dataset contains:

Render each field exactly as given:

Layers

Elonn has exactly two layers, Carry and Field. There are no others. A Runtime must not add a third layer. The terms "window", "panel", "card", "workspace", "Results pane", and "Entry" are presentation or interface structures. None of them is a layer.

Each Object is placed on one layer by its Placement. A Placement's type is carry or field, and it names the Object it places.

An Object does not change type when it moves between layers. Its Placement alone determines the layer.

Entry

Entry is Elonn's single member-facing point of entry. It accepts member input and submits it to the platform as a Call.

Results pane and Findings

A Finding is a result returned for presentation in the Results pane. It references one Object or Collection and does not duplicate it. A Finding is not a Placement, so it places nothing on a layer.

Objects on Carry

An Object presented on Carry has a title bar and a content area.

The title bar identifies the Object and holds these controls:

The title bar and the content area's appearance are the Runtime's choice. The behavior above is required.

Navigation within an Object

Input mapping

Canonical actions are defined by meaning, not by gesture. The canonical actions in this guide are open, focus, alt focus, back, collapse, and close. A Runtime maps its own input to them: a tap, click, pointer press, controller pinch, or voice command can each open an Object. Do not encode a gesture as the canonical difference between focus and alt focus. Elonn Runtimes span web, Android, desktop, and XR, and they do not share an input modality.

Presenting Actions and arguments

An Action is a capability an Object offers. Invoke it through its operation_invocation, which names the Service and operation, carries any arguments already known, and identifies the target.

When an operation needs arguments from the member, the Runtime renders a form from the operation's argument schema, which the Service publishes in its Contract. The Runtime is the authority for presentation of those arguments. The contract is the authority for each argument's type, required status, enumerated values, and labels. Render them as follows.

Labels

Argument sources

Argument types

Recognize these treatments from the declared type and constraints.format alone. Do not infer them from a Service id, an Object type, an operation id, or an argument name.

Entry points

A Service may declare entry points: its standalone human entrances. Present them using their label and purpose. Invoking one submits its operation with its preset arguments. Do not treat model_selectable as a presentation rule. That flag governs whether a reasoning Model may select an operation, not whether a member can use it.

Object content

Object type values are defined by the Service that produces them. The canonical model does not enumerate them. A Runtime renders an Object according to its declared content format, not by its type.

Field presentation

Geographic distance is data. Radial position is presentation.

A Field Object carries a geographic location. The canonical model defines no distance unit for Field. Maps owns the Field data, and it does not decide how a Runtime presents it. Presentation is the Runtime's responsibility.

A Runtime presenting Field in space must follow these rules:

The Android XR Runtime currently places each geographic Object at its true bearing on a fixed horizontal radius of 3 m, and keeps the real distance as Object information. This is the first implementation of the policy, not a fixed value. A change to it is a Runtime decision and must be recorded as one.

The Runtime needs the member's position and heading to place Field Objects by bearing. If location or heading is unavailable, the Runtime shows that it is waiting for them. It must not place Objects at a guessed position.

Spatial safety

A spatial Runtime presents content in the member's real view. It must never obstruct that view with opaque surfaces.

Spatial safety violations are Critical under review, because they can affect the member's physical safety.

Choosing a presentation

Choose the presentation from the device's advertised capability. Do not attempt the spatial path and fall back to flat presentation when it fails.

On Android, the spatial presentation is selected by the android.software.xr.api.spatial system feature. Ordinary phones use camera passthrough. Headsets use spatial presentation.

Catching an exception to decide the presentation hides real failures and makes behaviour depend on errors instead of the device. A Runtime that cannot run its spatial presentation on a device must say so, not silently use another one.

Errors and status

Terminology

Use canonical terms as defined in the glossary, terminology/glossary.xml. The distinctions that most often go wrong in a Runtime are:

Do not invent synonyms for canonical terms. Do not name identifiers, routes, payload keys, or UI copy with a term that contradicts the glossary.

Verification

A Runtime is not verified until it has been run on each device class it claims to support.

Review checklist

A Runtime change is reviewed in this order of priority: architecture, correctness, security, maintainability, operations, performance, UX consistency, style. Check in particular:

Appendix: sources

These are the normative and supporting sources from which this guide is derived. Runtime authors normally need them only when implementing canonical structures or resolving an ambiguity.