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:
- receive member interaction;
- authenticate Members through the API;
- construct canonical Calls;
- submit Calls to World;
- receive canonical Datasets from World;
- present those Datasets;
- execute Runtime-specific presentation behavior.
A Runtime SHALL NOT:
- determine member intent;
- perform orchestration;
- communicate directly with Conductor, Services, or Models;
- determine the canonical content or meaning of anything it presents.
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.
- Load the authentication form for a mode with the identity auth-form endpoint, then submit it to the identity endpoint it names.
- Send the access token as
Authorization: Bearer <token>on every World call. - Log out through the identity logout endpoint, sending the token.
- Store the token securely for the device. A token the platform rejects (HTTP 401) must cause the Runtime to return to sign-in, not to retry silently.
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:
objects: the Objects in the member's world, each withtype, a singletitle, a singlesummary, andcontent.actions: the Actions the member can take. Each has anoperation_invocationandavailability.collections: groups of Objects.placements: which Objects sit on which layer (carryorfield).findings: the results for the Results pane, newest first.resources,relationships: references to external content. Do not treat them as URLs to open.errors: problems encountered while processing the Call, each with a severity.context: navigation state, focus, and status that World owns.
Render each field exactly as given:
- Titles and summaries. Read the single
titleandsummaryfor each Object and Collection, and the singletargetfor each Action. World has already resolved them. Do not walk a fallback chain acrosscontent, and do not invent placeholder text when a field is empty. - Actions. Invoke an Action only through its
operation_invocation. Render its state fromavailability.state(enabledorunavailable) and showavailability.reasonwhen unavailable. Do not compute availability from the Action's shape, and do not treat a URL string as an Action. - Status. Render
context.status.messageand style it bycontext.status.severity(ok,notice, orerror). Do not inspecterrorsto decide severity or write your own status copy. - Focus. Highlight the Object named in
context.focus.object_id, or none if it is"". Do not pick a focused Object of your own, and do not carry a previous selection forward.
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.
- Carry presents non-geographic Objects: the member's personal layer, which travels with the member. Objects opened from Findings, Dashboards, and other interactions go on Carry unless they are explicitly placed on Field. How a Carry Object is shaped (a panel, card, movable window, or head-locked area) is a Runtime choice.
- Field presents Objects anchored to surrounding reality. The next sections cover how a Runtime presents Field.
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.
- Entry is presented on Carry.
- No other permanent interface element is presented alongside Entry. Diagnostic information may be shown temporarily during development, and it is not part of the layout.
- Entry consists of a form field and its controls. The controls are: microphone indicator (when voice input is available), submit (when the Runtime needs one), clear, and show/hide.
- When all controls are present, the order is: form field, microphone, submit, clear, show/hide. Omit a control the Runtime cannot provide without changing the order of the rest.
- The form field occupies the leftmost portion of Entry.
- The microphone toggles voice input. Submit sends the current Entry content as a
world.composeCall. A Runtime may omit a visible submit control if it has another appropriate way to submit. - Clear empties the Results pane (
world.clear). It does not clear Entry and has no effect on Carry, Field, or Objects placed on either layer. - Show/hide collapses or reveals the Results pane. It does not hide Entry. When the Results pane is collapsed, only Entry remains visible.
- There is no title bar above Entry.
- The shapes, dimensions, and visual treatment of Entry are the Runtime's choice. Entry is the concept; a bar or panel is one presentation of it.
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.
- Render the Results pane only from the Dataset's
findingslist. Do not treat every unplaced Object as a Finding. - The Results pane exists only while it contains Findings. When it has none, do not display it.
- The Results pane is cumulative and newest first. The order of
findingsis the display order. - Each Finding is shown as a card or another presentation suited to the Runtime.
- Focusing a Finding opens its Object on Carry. Submit
world.focuswith the Object's id incontext.runtime_state.origin_object. - A Finding stays listed until
world.clear. Focusing, navigating, or closing its Object does not remove it. Do not remove a card from the Results pane because its Object was opened. - A Finding's Object may also be placed on Carry or Field. The two are independent: one does not imply the other.
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:
- Back. Available only when the Object has a previous navigation state. It submits
world.backwith the Object's id inorigin_object. - Collapse. Collapses the content area, leaving only the title bar on Carry. Expanding restores it. Collapsing does not close the Object, remove it from Carry, or change its content or navigation state.
- Close. Submits
world.close, which removes the Object from Carry.
The title bar and the content area's appearance are the Runtime's choice. The behavior above is required.
Navigation within an Object
- An Object opened from a Finding is the container for further interaction with its content. Interaction within it changes the content shown, not the number of Objects on Carry.
- Following a link inside an Object navigates within that Object. It never opens another Object on Carry.
- Navigation history belongs to the Object. Back returns the Object to its previous content or navigation state. It does not open another Object, close the current one, or change its Placement.
- Breadcrumbs are not part of the navigation model.
- Focus a semantic region of an open Object with
world.focus_region, naming the Object inorigin_objectand the region incontent.region. A region focus is pushed onto the same history as a document change, so back undoes either. - Alt focus opens a result as a new Object instead of routing it into the Object the interaction came from. For a link, omit
context.runtime_state.origin_objectfrom the Call. World then composes the result as a fresh Object. Alt focus does not change any Object already open. - Use World's
context.objectsentry for an Object to know its title, depth, and history. Do not keep your own history for it.
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
- Display the text that World delivers for each argument's
label_ref, and for each enum value'senum_label_refs. Displayhelp_reftext beneath the field when present. - Never display a
*_refkey, and never derive a label by humanising a wire key. - Enum values are shown with their labels, not their raw values.
Argument sources
modelarguments are the member's to fill. Render them as form fields.contextarguments are resolved by the platform. Never present them to the member and never give them labels.
Argument types
string: a single-line field. A string withconstraints.format: markdownis a multiline editor that preserves line breaks. Its content is Markdown source.integerandnumber: a numeric field.boolean: a yes or no control.array: a list value. Its items follow the item schema the Service declares.datetime: a date and time picker. The value is a naive wall-clock string with no timezone offset, for example2026-09-16T21:09:20. Do not render it as free text.geo_point: a real map with a pickable or draggable point. Do not render separate latitude and longitude fields.drawing_operation: a live drawing surface. It shows the marks the Object already carries and captures new freehand input, which becomes the argument's value on submission.
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.
content.format: drawing_surfaceis an editable 2D surface a member draws on, independent of its type. Render the surface'sgraphics_resource, which is an SVG Resource holding the current rendered marks. Showpreview_resourcewhere a static thumbnail is wanted. Add marks through the Object's own Action that carries adrawing_operationargument. Do not render fromsource_resourcedirectly, and do not read its Drawing Operations to decide how a mark looks.content.format: markdownand other declared formats are rendered by the Runtime's own presentation of that format.- An Object whose type or format the Runtime does not recognise still shows its
title,summary, and its Actions. Do not guess at its content.
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:
- Bearing is meaningful. An Object that lies north of the member appears north of the member, relative to the member's own orientation.
- Radius is presentation. The Runtime may place Objects at a comfortable distance instead of their true distance. A Runtime must not place distant Objects beyond the member's view, where they are invisible.
- Actual distance remains available. Keep it as Object information, and show it when the Runtime chooses to. Do not discard it.
- Presentation is not canonical. Never write a radial choice or a rendered position back into canonical data.
- Only World's Field placements are rendered. Do not decide on your own which geographic Objects belong in Field.
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.
- No full-view occlusion. Do not present a background, scrim, or window fill that covers the member's main field of view. Window and root backgrounds must be transparent unless the Runtime has a specific reason and records it.
- Bounded chrome. Windows and panels occupy only the space their content needs. Default placement must not put interactive chrome in the centre of the member's view.
- Readable on any background. Text and controls must stay legible over whatever is behind them, including the real world. Check contrast on the device itself, not only in a design tool.
- Honest absence. When a required capability is unavailable (location, camera, scene access, the spatial session), the Runtime says so. It must not render a placeholder that looks like working content.
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
- World reports problems in the Dataset's
errors, each with aseverity. Show the status World resolves incontext.status. Anoticemeans the response is intact with a dependency problem. Anerrormeans the response is incomplete. - Show a failed Call as a failure. Do not show stale content as if it were current.
- When World is unreachable, show that state. Do not invent or retain content as if it were fresh.
Terminology
Use canonical terms as defined in the glossary, terminology/glossary.xml. The distinctions that most often go wrong in a Runtime are:
- Layers. Carry and Field are the only layers. Window and workspace are neither layers nor Placement types. "Window" is a presentation term for an Object on Carry, and must not be used as an architectural concept in code.
- Card and window. A card previews or launches an Object, and it is renderer-level. A window is a movable, resizable, focusable rendering of an Object on Carry. Do not use the two as synonyms.
- Open. Open is the canonical action. Do not use "tap" or "click" as synonyms for it in names, documentation, or interface copy.
- Focus and alt focus. Focus opens or redirects the member's current Object. Alt focus opens a new Object and leaves the current one unchanged.
- Finding and discovery. A Finding is a result in the Results pane. Discovery is the social graph traversal that determines who a member can see. Do not conflate them.
- Message, conversation, and reply. Message is reserved for direct one-to-one threads owned by Messages. A reply extends a conversation or event discussion. These are not interchangeable.
- Event. Event, unqualified, is a social event. A calendar entry is a Time item.
- Service Publication and Service discovery. A Service Publication is the document a Service publishes so that Service Registry can index it. Service discovery is Conductor's responsibility. A Runtime does neither.
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.
- Verify on the target emulator and, where one exists, on the physical device. Phone verification does not verify a headset Runtime, and emulator verification does not verify a physical device.
- Record what was run, on which device, and what was seen. Screenshots and logs are the evidence.
- A claim that a presentation works requires that it was observed on the device. A build that compiles is not evidence that it works.
- Do not ship a presentation whose spatial behavior has not been checked on device.
Review checklist
A Runtime change is reviewed in this order of priority: architecture, correctness, security, maintainability, operations, performance, UX consistency, style. Check in particular:
- The Runtime calls only the API for authentication and World for content. It never calls Conductor, a Service, or a Model.
- The Runtime renders from the Dataset and holds no canonical state of its own.
- There are only two layers, and no presentation term is treated as a layer or placement type.
- Runtime-specific behavior does not leak into shared logic, and no Service-specific behavior is hard-coded in the Runtime.
- Argument rendering is driven by declared types and formats, not by names.
- Field presentation keeps geographic data canonical and does not write presentation back.
- No opaque surface covers the member's main field of view.
- Capabilities declared to World match what the Runtime presents.
- The presentation was verified on each device class it claims to support.
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.
canonical/dataset.json,canonical/call.json,canonical/context.json: normative structures.canonical/object.md,canonical/action.md,canonical/finding.md,canonical/placement.md,canonical/collection.md,canonical/resource.md,canonical/relationship.md,canonical/error.md: canonical structures.canonical/svg-profile.md,canonical/drawing-operation.md: drawing content.canonical/html.md: HTML interpreted into canonical content, including semantic regions.terminology/glossary.xml: the canonical terminology and its distinctions.contract-authoring-guide.md: how a Service publishes argument schemas, labels, and entry points.ELONN.md: the platform architecture.