Runtime Contract
Status: Normative runtime contract source. Sections that explicitly describe current compatibility output record migration reality, not design authority for new runtime dataset work.
This document is the authoritative specification for what every Elonn runtime must implement. It is defined from the World Dataset Contract outward, not from any specific runtime. The fresh World Dataset Contract is documented in world-dataset-contract.md.
The contract goal is decision-complete runtime implementation: a competent runtime engineer must be able to build a new Elonn runtime for a new device from this document, the service contracts, examples, and conformance checks without reading existing runtime, World, or service implementation code to infer behavior.
Platform runtime pages describe implementation status and platform constraints. This document is the normative runtime contract.
What A Runtime Is
A runtime is a consumer of the canonical runtime dataset produced by World. It owns local state needed for rendering, input, projection, lifecycle, and recovery. It does not own identity, Social, Messages, Time, Maps, Find, Surface, workspace, permission, or business state.
The target architecture is:
Service object sources
-> World canonical model
-> Canonical runtime dataset
-> Runtime adapter
-> Platform renderer
The runtime dataset is transparent data. It contains objects, contexts, actions, workspace state, field state, findings, capabilities, and fallbacks. It does not contain service panel payloads, Surface records, stack records, right-rail records, dock definitions, renderer hints, HTML, embedded browser content, or platform-specific UI instructions.
Every runtime consumes the same logical dataset. Runtimes do not consume raw service payloads, current compatibility payloads, an implementation-private World model, or existing runtime implementation behavior.
Build Target
A new runtime is complete when a member can authenticate, request the canonical runtime dataset from World, build runtime state from that dataset, construct a platform-native scene, render objects and contexts, handle local interaction, dispatch World-published commands, receive an updated dataset, and update the scene without implementing service business logic.
Runtimes never render arbitrary HTML, execute resource JavaScript, call services directly, derive actions from URLs, infer permissions from missing fields, or hardcode service behavior.
Implement these responsibilities. Module names and language boundaries are adapter-specific:
| Module | Required responsibility |
|---|---|
| Runtime config | Select World base URL, login URL, runtime id, version, and capability declaration without code changes |
| Auth client | Obtain an Elonn credential, call World identity endpoints, and attach the credential to World requests |
| World client | Fetch the canonical runtime dataset, resolve World-relative command URLs, post World commands, and receive refreshed datasets |
| Runtime state | Validate the dataset, index objects/actions/contexts, track local UI-only state, and replace authoritative state from World updates |
| Scene construction | Convert runtime state into platform-native structures such as DOM, SwiftUI, Compose, Unity scene graph, or future scene graphs |
| Renderer | Draw the scene with platform capabilities without adding business logic |
| Interaction | Convert platform input into World command dispatches or local presentation changes |
| Projection | Convert dataset placement, field, and spatial data into platform coordinates |
| Fallback handling | Render unavailable, unsupported, denied, empty, and degraded states exactly from the dataset |
Do not build service clients for API, Social, Messages, Maps, Time, Surface, or Find. The only runtime-facing upstream is World.
Reference Runtime Baseline
The fresh world.elonn.local runtime harness is the current reference
implementation baseline for new runtime architecture. It is not the product Web
runtime, and its DOM scene is not normative for Android, iPad, XREAL, Unity, or
future runtimes.
The baseline exists to prove component boundaries against the World Dataset Contract:
| Runtime component | Reference file | Responsibility proven |
|---|---|---|
| World client | world.elonn.local/public/assets/runtime-world-client.js |
Requests POST /world/session, sends World-owned profile/context, dispatches only World action endpoints, and receives refreshed datasets. |
| Runtime state | world.elonn.local/public/assets/runtime-state.js |
Validates elonn.world.dataset, indexes objects/actions/collections/resources, tracks local selected object and action progress, and replaces state from returned datasets. |
| Scene construction | world.elonn.local/public/assets/runtime-scene.js |
Converts runtime state into a platform scene without service logic. The current scene target is DOM; other runtimes use native scene graphs. |
| Renderer | world.elonn.local/public/assets/runtime-renderer.js |
Applies scene output to the platform renderer without owning business state. |
| Interaction | world.elonn.local/public/assets/runtime-interaction.js |
Converts platform input into local selection changes or World action dispatches. |
| Projection | world.elonn.local/public/assets/runtime-projection.js |
Converts runtime objects and relationships into platform-specific display labels/coordinates without changing semantics. |
The browser harness is acceptable reference material only for architecture and conformance. Future runtimes must preserve the same component responsibilities and World-only upstream boundary, but they must choose their own platform scene construction, renderer, interaction model, and projection.
Rendered acceptance is part of the baseline. The World service test
world.elonn.local/tests/rendered-runtime-harness.mjs loads the harness in
Chromium, verifies provider-backed collections, selected object details,
resources, action controls, and action-response dataset replacement, and proves
the browser runtime does not call Find or provider endpoints directly.
Transparent Runtime Dataset
The target canonical runtime dataset has this top-level shape:
| Field | Meaning |
|---|---|
contract |
{name, version} identifying the runtime dataset contract |
member |
Authenticated member context needed for presentation, never reusable credentials |
capabilities |
Applied runtime capabilities and explicit unsupported capabilities |
workspace |
Current working set, focus, order, placement, and continuity state |
objects |
Runtime-presentable World objects with stable World ids and source authority references |
contexts |
Navigation/control groups tied to objects, workspace, field, or findings |
actions |
Runtime-dispatchable semantic command descriptors routed through World |
field |
World-anchored field state, semantic field controls, and field-presentable objects |
findings |
Discovered candidates from Find before or during promotion to objects |
fallbacks |
Explicit degraded, unavailable, unsupported, empty, or denied states |
sources |
Diagnostic source metadata, never service endpoints for runtime calls |
The dataset must be complete enough for a runtime adapter to render without reading Web, Android, iPad, Cardboard, World implementation code, service implementation code, or compatibility payload examples.
Dataset Rules
objects[]is the primary display set. Main and secondary display entities are objects with stableworld_object_id,object_type,source,title, state, permissions, actions, relationships, placement, and focus metadata.contexts[]is semantic navigation and control intent. A context is not a right rail, left rail, sidebar, sheet, menu, or panel. Runtimes may project a context into any of those forms.workspaceis semantic working-set state. It is not a stack, deck, dock, or window layout. Runtimes may project workspace order and focus into a stack, grid, spatial room, command list, or nonvisual sequence.fieldis world-anchored state. It is not a map widget and not a marker list. Field controls are semantic selectors and toggle groups such as radius and place category filters. Runtimes choose marker, list, spatial anchor, audio, or other projection.findings[]are candidates. A finding becomes a runtime-presentable object only when World composes or promotes it intoobjects[].actions[]are semantic commands. Runtimes dispatch the declared command and must not reconstruct service or World URLs from ids, labels, object types, or source references.fallbacks[]are required state, not optional text. If a capability, permission, service, object, field, or command is unavailable, the dataset must say so explicitly.- Unknown object types, context kinds, action types, fields, or capabilities are ignored or rendered generically according to explicit fallback data. Unknowns must not crash a runtime or cause service-specific inference.
Runtime Lifecycle
Every runtime follows this lifecycle:
Authenticate
-> request canonical runtime dataset from World
-> build runtime state
-> construct platform scene
-> render
-> receive user interaction
-> dispatch World command
-> receive updated runtime dataset
-> replace authoritative runtime state
-> update platform scene
Persistent state changes always flow through World. A runtime may maintain local presentation state such as scroll position, focus ring, expanded local controls, cached textures, or retry timers only when that state does not contradict the latest World dataset.
Completion Standard
The contract is complete only when a runtime can implement these rules without reading an existing runtime or service implementation:
- World response data is authoritative for objects, contexts, actions, workspace, field, findings, permissions, relationships, and fallbacks.
- The runtime state layer validates the dataset, indexes by stable ids, replaces authoritative state from updates, and preserves only non-conflicting local presentation state.
- The renderer adapts presentation to platform capability but does not create product structure, business rules, permissions, or service routes.
- Interaction dispatches World-published commands and never mutates persistent business state directly.
- Conformance fixtures prove that the same canonical runtime dataset can be projected by at least two runtime capability classes without changing object identity, action meaning, permissions, relationships, focus, field state, findings, or fallback semantics.
Compatibility Appendix
The sections below describe the current runtime v2 /world/session
compatibility contract. They are retained only to explain existing migration
state and tests. They are not the target runtime dataset, and no new runtime or
service capability should use them as design authority.
1. Contract sources
Every runtime session begins by calling these endpoints. All relative paths resolve against world.elonn.com.
| Endpoint | When | Purpose |
|---|---|---|
GET /world/identity/me |
On load, after any 401 | Authenticated member identity — World proxies to API |
GET /world/session |
On load, after find query | Full runtime contract: surfaces, stacks, commands, field objects, Social objects, Messages objects, member directory |
GET /world/panels/{service} |
When focusing a surface with content_source.kind = runtime_panel |
Service payload for that durable surface: title, summary, sections, actions, and service-specific state. Canonical right rail content is delivered as right rail surfaces, not inferred by runtimes from panel payloads. |
POST /world/find/query |
When member submits a find query | Returns updated surface_runtime with finding surfaces |
Runtimes never call api, social, messages, maps, time, surface, or find directly. World is the only upstream.
The full GET /world/session payload is specified in world-contract.md.
Request rules
- Send
Accept: application/jsonon every World JSON request. - Runtimes send JSON request bodies with
Content-Type: application/json. - Browser form submissions may use
application/x-www-form-urlencoded; World accepts both JSON and form-encoded bodies for runtime form and find writes. - Web runtimes send credentials with cookies. Native runtimes send
Authorization: Bearer <elonn_api_token>. - Include
X-Elonn-RuntimeonGET /world/session; see Compatibility capability declaration. - Treat all 2xx responses as success and all non-2xx responses as failures. Do not infer success from response text.
2. Contract objects
From GET /world/session
surface_runtime.surfaces[]
Each surface is a durable record scoped to the authenticated member.
| Field | Type | Notes |
|---|---|---|
surface_id |
string | Stable runtime identifier, e.g. surface_social |
surface_type |
string | Normalized type, e.g. conversation_surface, finding_surface, profile_surface |
title |
string | Display label |
service_binding |
object | {service_id, resource_type, resource_id} — empty object {} when absent |
content_source |
object | {kind, url} — kind is runtime_panel or inline; empty {} when absent |
runtime_state |
object | {summary, details: [[key, val], ...]} — PHP serializes empty as []; accept both |
permissions |
object | {can_detach, can_pin, can_share, can_field_anchor} — empty {} when absent |
rendering_hints |
object | {preferred_size, interaction_mode} — non-authoritative; empty {} when absent |
placement |
object | {mode, metadata: {stack_id, x, y, width, height, z}} |
Placement modes: stacked, docked, detached, shared, field_anchored.
The title field is required surface chrome data. The runtime renders it in a
surface title bar with a show/hide content control for every surface. Content
visibility is UI state unless World/Surface later returns a specific persisted
surface state value; either way, toggling visibility never changes stack
membership, placement, focus, Field objects, or finding surfaces.
A finding surface is a surface with surface_type = "finding_surface" and placement.mode = "detached". Finding surfaces appear after a successful find query and carry runtime_state.finding. A translated finding also carries runtime_state.surface_object.
A Surface Object has surface_object_id, source_finding_id, object_type,
title, summary, primary_url, branding, content, actions, and
runtime_hints. primary_url is provenance, not a navigation instruction.
actions is always an ordered array of semantic descriptors with id,
label, type, and optional targets. A runtime displays the supplied label.
It must not derive labels or availability from object type, provider, route, or
a string action name.
A place Surface Object may omit primary_url and instead carry
content.location plus runtime_hints.map. The map contract contains a
viewport, provider-neutral raster layer declarations, markers, and attribution.
Render the declared layer with native runtime components. Do not parse provider
search responses or use an embedded browser.
shell.dock.items[]
Dock items are ordered contract data. Render each item from its label, icon, and attached action. Do not hardcode service names, dock ordering, or service-specific handlers.
field_runtime.controls[]
Controls are generic selectors, toggle groups, and action items. Category ids
such as coffee are opaque product data. A runtime renders labels and dispatches
attached actions; it does not maintain a category registry.
services[]
Each service descriptor publishes its entry surface, content source, workspace, actions, and optional renderer hint. Resolve opening and navigation through this descriptor. Do not branch on service ids or recognize service URLs in the runtime router.
Renderer hints are optional optimizations. Unknown hints use the generic surface or panel renderer and remain usable from title, summary, sections, objects, and supported actions.
surface_runtime.stacks[]
| Field | Type | Notes |
|---|---|---|
stack_id |
string | Stable placement target, e.g. carry_primary, left_context, right_context, finding_overlay |
stack_type |
string | e.g. carry_stack, context_stack |
region |
string | e.g. carry, context |
display |
string | e.g. full, rail |
slot |
string | Optional layout slot, e.g. left, right, center; may be empty |
orientation |
string | Stack navigation axis |
focused_surface_id |
string|null | Current focus |
surface_order |
string[] | Ordered surface ids for this stack |
viewport_id |
string | Viewport that presents this stack |
Stack ids identify placement targets. Their role is described by stack fields
such as region, display, slot, and orientation. Adapters must not infer product
meaning from a specific id. A runtime renders every World-supplied stack whose
display and region it supports; unsupported displays must degrade to a
generic ordered list rather than being dropped silently. The canonical stacks
currently published by Surface are:
| Stack | Meaning |
|---|---|
carry_primary |
Center stack for dock-activated service panels and opened object surfaces |
left_context |
Runtime and member context rail |
right_context |
Service navigation or field controls rail |
finding_overlay |
Detached current finding surfaces |
The runtime must not remove any surface from a stack because of a service id, surface id, URL, title, or object type. If a runtime wants to hide a stack for a workspace mode, it keeps the stack in state and only changes presentation visibility.
surface_runtime.commands
focus_surface — POST URL for writing focus: POST {url} with {surface_id}
reorder_stack — POST URL for writing order: POST {url} with {surface_order: [...]}
update_placement — POST URL pattern for placement writes
translate_surface — POST URL pattern for translating a persisted resource finding
open_finding — POST URL pattern for opening a place finding as a durable map surface
World may publish additional placement aliases such as detach_surface, dock_surface, field_anchor_surface, and share_surface. Those aliases resolve to World placement writes; the required minimum command set is focus_surface, reorder_stack, and update_placement.
translate_surface is required when translatable resource findings are
present. Replace {surface_id} and send {}. Apply the returned
surface_runtime.
open_finding is required when place findings are present. Replace
{surface_id}, send {}, apply the returned surface_runtime, enter carry
mode, and focus the returned map_surface. Reopening the same provider/source
id must not create another durable surface. The original finding surface
remains on finding_overlay until World replaces or clears that layer.
Command request bodies:
POST {commands.focus_surface}:
{"surface_id": "surface_social"}
POST {commands.reorder_stack}:
{"surface_order": ["surface_social", "surface_calendar", "surface_messages"]}
POST {commands.update_placement} after replacing {surface_id}:
{
"placement_mode": "detached",
"placement": {
"stack_id": "carry_primary",
"region": "carry",
"display": "free",
"x": 24,
"y": 48,
"width": 260,
"height": 148,
"z": 1
}
}
field_runtime
Geographic objects composed server-side by world from the maps service. The runtime does not call maps directly.
Field data is requested through GET /world/session. When the runtime has a member/device location, include these query parameters:
| Query parameter | Type | Default | Notes |
|---|---|---|---|
lat |
float | none | Member/device latitude |
lon |
float | none | Member/device longitude |
radius |
integer | 1000 |
Meters |
categories |
comma-separated string or repeated values | all standard categories | Field place categories |
When lat and lon are omitted, field_runtime.objects is empty and field_runtime.origin is null. The runtime must still render the field shell and controls.
Top-level field runtime shape:
| Field | Type | Notes |
|---|---|---|
contract |
object | {name: "elonn.field.runtime", version: 2} |
origin |
object|null | {latitude, longitude} for the returned object set |
radius_meters |
integer | Applied radius |
field_width |
integer | Logical panorama width for adapters that use it |
controls |
Control[] | Ordered selectors and toggle groups |
objects |
Object[] | Generic object envelopes with marker-capable presentation |
source |
object | Diagnostic source metadata; do not call it directly |
field_runtime.objects[] fields:
| Field | Type |
|---|---|
id |
string |
type |
semantic object type |
category |
opaque product data |
title |
string |
summary |
string |
presentation |
card/marker preferences |
location |
latitude, longitude, distance, bearing, and local offsets |
actions |
ordered semantic action descriptors |
attribution |
required provider attribution |
Other session fields
services.social.objects—{conversations, communities, events, presence}as integer countsservices.messages.objects—{threads}for open one-to-one member message thread summariesservices.identity.members[]— member directory entries with{id, email, display_name}
From GET /world/panels/{service}
Panel payload shape:
| Field | Type | Notes |
|---|---|---|
kind |
string | Service identifier, e.g. social, time, find |
view |
string | Active view within the panel |
title |
string | Display title for the containing panel |
summary |
string | One-line descriptive summary; presentation depends on region |
nav |
array | Legacy or in-panel navigation items; not the canonical right rail |
sections |
array | Panel body sections and their items |
actions |
object | Top-level action map |
action_descriptors |
array | Ordered semantic actions and producer-described form controls |
The nav array is service-owned panel content for runtimes that need in-panel
navigation. Each nav item has an id, a label, and an optional action URL.
Items without an action are labels, not buttons. Runtimes may render nav
inside the surface that loaded the panel, but nav does not define the
canonical right rail. Canonical right rail content comes from right_context
surfaces and their panel sections, item actions, and action_descriptors.
The sections array is service-owned content grouped for the panel body. Each section has a title and an items array. Each item has an id, title, optional summary, optional metadata, and optional actions.
Runtimes must treat panel payloads as transient service-owned content unless World also supplies a durable surface record for the same object. A panel payload does not by itself create a durable surface. A durable surface is authoritative only when it arrives through surface_runtime.surfaces[].
Panel payload state must be attached to the durable surface or modal panel that requested it. A single global "center payload" is not a valid model unless it is keyed to the currently focused durable surface and cleared when focus changes. A runtime must not replace a durable surface title, identity, placement, or stack membership with panel payload data.
If sections is empty or missing, full panel presentations must still render
the title and summary plus an empty-state message. Compact rail
presentations render the surface title as chrome and may omit summary/body text
that is not actionable. If nav is empty, the surface must not invent
navigation.
Additional service-specific keys are allowed and must be ignored when unknown.
When action_descriptors is present, render it instead of deriving behavior
from action-map keys. A submit_form descriptor supplies its method, World
URL, and ordered controls. Generic runtimes render text, textarea, and selector
controls without knowing the product meaning of the action id.
Messages Route Reference
Messages is the reference vertical slice for service-owned panel content and World-owned runtime placement:
messages.elonn.localowns message threads, selected thread messages, recipient directory context, and producer action intent. Its/runtime/panel/messages?format=jsonpayload publishesthreads,selected_thread,messages,members, andaction_descriptors; thestart_threaddescriptor uses a member-backedrecipientselector when member options are available.world.elonn.localis the runtime gateway./world/panels/messagesrelays the Messages panel and normalizes thread objects./world/panels/messages/railpublishes compact right rail content with a Threads row andStart threadsubmit_formdescriptor.surface.elonn.localowns durable placement.surface_messageslives incarry_primaryand loads/world/panels/messages;surface_messages_raillives inright_context, loads/world/panels/messages/rail, and declaresplacement.metadata.matches_surface_id: "surface_messages".- Runtimes load those World URLs from
content_source, render the active matching right rail surface, and routeopen_panel/submit_formactions to the matched center surface. Runtimes must not invent Messages rail entries from service id, URL, or legacy panelnav.
From POST /world/find/query
Body:
{
"query": "coffee",
"scope": "nearby",
"origin": {"latitude": 47.6062, "longitude": -122.3321},
"radius_meters": 5000
}
The runtime chooses and visibly displays scope. Default to nearby when an
existing runtime location is available. Otherwise default to everywhere and
show that location was unavailable. Do not start a second permission flow for
Find. Nearby without an origin returns location_required.
term near place is an explicit named-location override. Find resolves the
place globally and applies its 5 km Nearby scope there. Find scope and radius
are independent of Field state.
An ok response contains an updated surface_runtime with detached finding
surfaces. Replace the returned surfaces and stacks. location_required and
provider_error keep the previous finding overlay visible and provide a
retryable status message.
If the response also includes a findings array, use it only for count/status text. The UI source of truth is still the returned surface_runtime.
The finding_overlay stack is the authoritative current query result layer. A
successful query replaces its complete finding membership. Zero results produce
an empty overlay without changing carry surfaces.
Finding surfaces are still durable surfaces. Render their title, summary,
finding metadata, and action descriptors from surface_runtime. Do not treat a
finding as a field marker unless World returns it through field_runtime.
Resource findings use translate_surface; place findings use open_finding.
Place finding opens create or focus a separate map_surface in carry_primary;
the finding surface itself remains on finding_overlay.
From POST /world/surface/surfaces/{surface_id}/translate
Send {}. On success, replace local surface_runtime and render
runtime_state.surface_object. Translation upgrades the same surface; its
identity and placement do not change.
3. Required state machine
A runtime must maintain this state. Names are specification names; each runtime may use its own idiomatic names.
Lifecycle
| State field | Type | Values |
|---|---|---|
status |
enum | idle / loading / ready / authRequired / unavailable |
identity |
object|null | {id, displayName, email} — null until authenticated |
Initial values: status = idle, identity = null.
Workspace
| State field | Type | Values |
|---|---|---|
workspaceKind |
enum | carry / field / find |
Initial value: workspaceKind = carry.
Carry
| State field | Type |
|---|---|
carrySurfaces |
Surface[] — from carry_primary stack order |
leftContextSurfaces |
Surface[] — from left_context stack order |
rightContextSurfaces |
Surface[] — from right_context stack order |
activeRightRailSurfaceId |
string|null — focused right rail surface for the active center surface or workspace |
stacksById |
Map\<string, StackRuntime> — every supported World-supplied stack |
focusedCarrySurfaceId |
string |
surfacePanelPayloads |
Map\<surface_id, PanelPayload> — loaded transient payloads keyed by durable surface |
surfaceCommands |
object — write URLs from surface_runtime.commands |
When carrySurfaces is empty (no items in carry_primary), focusedCarrySurfaceId is null. The runtime must not fall back to left_context or right_context surfaces to fill the carry area.
Initial values: arrays are empty, stacksById = {},
focusedCarrySurfaceId = null, surfacePanelPayloads = {},
surfaceCommands = {}.
Find
| State field | Type |
|---|---|
findQuery |
string |
findStatus |
string|null — human-readable status after a query |
findScope |
enum — nearby / everywhere |
findScopeExplicit |
boolean — whether the member selected the current scope |
findingSurfaces |
Surface[] — from the finding_overlay stack order |
findingOverlayLimit |
integer — how many finding surfaces are visible (default 8, increments of 8) |
Initial values: findQuery = "", findStatus = null,
findScope = nearby when location exists and everywhere otherwise,
findScopeExplicit = false, findingSurfaces = [], and
findingOverlayLimit = 8.
Field
| State field | Type |
|---|---|
geoObjects |
GeoObject[] — from field_runtime.objects |
fieldPlacesRadius |
integer — tiers: 500 / 1000 / 5000 m |
fieldPlaceCategories |
Set\<string> — 10 standard categories |
deviceOrientation |
platform-specific — heading degrees, attitude matrix, or equivalent |
Standard field place categories: coffee, food, gas, hotels, shopping, parks, transit, marinas, museums, landmarks.
Initial values: geoObjects = [], fieldPlacesRadius = 500, all standard field place categories selected.
Transient panel
| State field | Type |
|---|---|
panelURL |
string|null |
panelTitle |
string |
panelOpen |
boolean |
panelBodyVisible |
boolean |
Initial values: panelURL = null, panelTitle = "", panelOpen = false, panelBodyVisible = true.
4. Required behaviors
These are the behaviors the runtime must expose to the user interface.
| Behavior | Trigger | Effect |
|---|---|---|
load() |
App launch or runtime session refresh | GET /world/identity/me; GET /world/session; apply surfaces/stacks/commands/field objects; set status |
focusSurface(surfaceId) |
User taps carry surface | Update focusedCarrySurfaceId; load panel if content_source.kind == runtime_panel; write focus |
openService(serviceId) |
open_service action |
Resolve the generic service descriptor and enter its declared workspace or entry surface |
openWorkspace(workspace, surfaceId) |
open_workspace action |
Enter the declared workspace and focus the supplied right rail surface when present |
enterFieldWorkspace() |
World dock/action opens Field | workspaceKind = field; keep Field markers visible; focus the Field control surface in right_context |
exitFieldWorkspace() |
World dock/action opens a non-Field surface/workspace | Leave Field workspace without clearing Field markers |
enterFindWorkspace() |
World dock/action opens Find | workspaceKind = find; keep detached findings visible; focus the Find search/control surface in right_context |
exitFindWorkspace() |
World dock/action opens a non-Find surface/workspace | Leave Find workspace without clearing detached findings |
setFindQuery(text) |
User types in find input | Update findQuery |
queryFind() |
User submits find query | POST query plus visible scope; send origin only for Nearby; apply returned surfaces and applied-scope status |
translateFinding(surfaceId) |
User opens or previews an html_resource finding |
POST the supplied translate_surface command; apply returned runtime; render surface_object |
openPlaceFinding(surfaceId) |
User opens a place finding |
POST the supplied open_finding command; apply returned runtime; enter carry mode and focus the returned map_surface |
clearFindings() |
User dispatches World-provided Find clear action | Apply the returned surface_runtime or command result; detached findings are not cleared by hiding panels or switching views |
showMoreFindings() |
User taps "show next" | Increment findingOverlayLimit by 8 |
openSurfaceAction(action) |
User invokes a surface or rail action | Dispatch the World-provided action without inferring service behavior |
openPanel(url, title) |
Surface action or nav item with no inline target | Open a transient loading or notice panel at URL |
showPanelBody() |
User asks to show panel body | Set panelBodyVisible = true |
hidePanelBody() |
User asks to hide panel body | Set panelBodyVisible = false |
closePanel() |
User dismisses modal | Clear modal panel state and remove it from view |
openSurface(surfaceId) |
User requests a durable object surface | Focus or open the durable carry surface for the object; keep it in surface_runtime |
openAction(url) |
Any action URL | Submit or navigate to the World action URL and refresh the affected surface or panel on success |
submitForm(fields, url) |
User submits a form | POST url with form fields; refresh panel or session on success |
setFieldRadius(meters) |
User selects radius | Update fieldPlacesRadius; re-fetch field session with new radius |
dispatchAction(action) |
Any rendered action | Execute a supported semantic action; disable unknown actions without crashing |
writeFocus(surfaceId) |
After focusSurface |
POST {commands.focus_surface} with {surface_id} |
State application rules
- Apply
surface_runtimeby indexing surfaces bysurface_id, then deriving each stack's surface list fromsurface_order. - Apply
right_contextas the canonical right rail stack. Its active surface matches the focused center surface or active workspace according to World and Surface focus/order data. - Render the active
right_contextsurface as contextual rail content. Do not render every surface inright_context.surface_orderas service buttons, tabs, or dock entries. - Resolve service content and navigation from
services[],content_source, and actions. Never infer a renderer from a service id or URL. - Ignore unknown additive fields. Apply declared fallback behavior to unknown services, icons, surfaces, controls, objects, placement, and actions.
- Normalize findings, Surface Objects, and panel section items into the common object envelope before rendering. Unknown object types use a generic title/summary/action card.
- Render actions from ordered descriptors. A known but locally unavailable action is disabled; an unknown action follows its fallback policy.
- Standard workspace/action types include
open_surface,focus_surface,open_service,open_workspace,set_field_filter,set_radius,submit_query,translate_surface,open_finding,clear_findings, and placement command aliases published by World. open_panelfrom a right rail item loads the supplied World URL into the matched center surface identified byplacement.matches_surface_id.submit_formfrom a right rail command opens the producer-described form in the matched center surface or active workspace. The runtime must not submit an empty form merely because the descriptor exists.- Preserve local UI-only state only when it does not contradict a fresh World response. World response data wins.
- After a successful panel action or form submission, re-fetch the current panel URL and replace the panel payload. Do not patch service-owned lists from runtime assumptions.
- A 409 or 422 form response is an inline form error. Keep the current panel payload and entered fields visible; do not mark the entire runtime unavailable.
- After
queryFind(), replace localsurface_runtimewith the returnedsurface_runtime, recompute stack lists, recomputefindingSurfaces, resetfindingOverlayLimitto 8, and leave the focused carry surface unchanged when it still exists. clearFindings()must use a World-provided action or returned runtime state. It must not delete durable surfaces through unlisted service calls.setFieldRadius()updates local filter state. If World exposes a radius-aware session endpoint later, use that World endpoint only; do not call Maps directly.- To refresh field objects after a field-control action, call
GET /world/sessionagain with the resulting location and filter inputs; apply the returned controls and objects.
5. Render model
Every runtime must render the primitives supplied by World. Spatial layout and presentation technology are platform-specific; browser rails are one adapter choice, not a contract requirement.
| Primitive | Required behavior |
|---|---|
| Shell and dock | Render ordered shell actions using platform-appropriate controls |
| Workspace | Present the active workspace declared by a service or action |
| Stack and surface | Preserve World order, focus, placement, title, content, and supported actions |
| Center carry stack | Render carry_primary display: full surfaces as full panel surfaces in an ordered carousel; neighbor surfaces remain full panels, not cards or title-only previews |
| Panel | Present transient content without treating it as a durable surface |
| Surface chrome | Render a title bar and show/hide content control for every surface; hiding content keeps the title bar visible |
| Right rail | Render the active right_context surface as compact contextual nav/controls; title is chrome, items/actions are the usable controls, summaries are not primary rail rows |
| Field and marker | Project or list field objects behind panels according to device capabilities |
| Detached findings | Render finding_overlay above field and behind carry/rail panels until changed by World-provided actions |
| Object and card | Render a generic title/summary/action presentation when no specialization exists |
| Control | Render known control primitives and disable unsupported controls safely |
| Attribution | Display required provider attribution without provider-specific branching |
When surface_calendar is open, Time must render native day, week, month,
agenda, and task views from the World Time workspace payload. It must support
appointment and task create/edit/delete actions, task completion, calendar
assignment, description, location, all-day state, priority, status, timezone,
recurrence, and reminder fields. It must also support calendar create, edit,
and delete, preserve view/date/timezone across refreshes, and disable
Social-owned mirror fields according to editable_fields. A generic list of
calendars and events is not a conforming Time workspace.
Minimum UI states
- If
status = loading, show a loading state in the primary runtime surface. - If
status = authRequired, show or open the login interface and provide a retry path after login. - If
status = unavailable, show a retryable unavailable state. Do not render stale service data as fresh. - If
carrySurfacesis empty, show an empty carry workspace. Do not synthesize default carry surfaces. - If a transient panel has no
sections, show itstitleandsummaryand an empty notice state. - If any surface's content visibility is false, keep the title bar visible and hide only the content container.
- If
panelOpen = false, remove the panel entirely. - If a required command is absent, do not synthesize a route. Disable the corresponding action or leave optimistic local state non-persistent.
- If there are no field objects after filtering, show an empty field state while keeping field controls usable.
- If there are no finding surfaces after a successful query, show a zero-results find state and keep the previous non-finding carry surfaces.
- If translation fails, keep the original finding visible and show a retryable inline error.
- Render Surface Objects with native components. Never inject source HTML or execute source scripts.
- If Find returns
location_required, keep existing findings and ask the member to enable location or include a named place. - Field markers and detached findings remain visible behind panels. Hiding a panel's content reveals them; it does not clear or mutate them.
- Background rendering of any service surface must not change
workspaceKind; only explicit member navigation changes workspaces.
6. URL resolution
https://orhttp://URL → use as-is- Path starting with
/→https://world.elonn.com+ path - Relative path →
https://world.elonn.com/+ path
All panel and action URLs in the world contract are relative paths. The runtime constructs absolute URLs for requests only; it does not hard-code service hosts other than world.elonn.com.
7. Error handling
| Error | Response |
|---|---|
| HTTP 401 on any request | Set status = authRequired; show auth panel |
| HTTP 403 on any request | Show unavailable or inline permission error; do not retry as another member |
| HTTP 404 on a panel/action URL | Show inline not-found error for that panel/action |
| HTTP 409/422 on write/form submit | Show inline validation/conflict error and leave existing runtime state in place |
Network/server error on load() |
Set status = unavailable with message |
| Panel load failure | Show error text in panel region; do not crash or leave region blank without message |
| Find query failure | Set findStatus to an error string; leave findingSurfaces unchanged |
| Find location required | Keep findings unchanged; show a location-required status |
| Resource translation failure | Keep the finding surface unchanged; show an inline retryable error |
| Form submit failure | Show error inline; do not dismiss the form |
Retries are user-initiated unless the platform provides a standard transient network retry. A retry must repeat the same World request with the same authenticated member credential.
8. Auth model
Runtimes authenticate through World. The identity endpoint GET /world/identity/me returns the authenticated member; World proxies to API internally. Runtimes do not call API directly.
The credential is the elonn_api_token value:
- Web: Sent as a cookie automatically via
credentials: 'include'. Login runs atelonn.com/account/loginin the same browser session. - Native (Android, iPad, headset runtimes): Present the configured login URL in a
WKWebView/WebView, complete the standard browser login, read theelonn_api_tokencookie from that login session's cookie jar, and send it asAuthorization: Bearer <token>on all requests to World. Native runtimes do not ask for a manual app token.
A 401 from any World endpoint means the credential is missing or expired. Set status = authRequired and show the login interface.
9. Runtime projection capability classes
Runtime capabilities describe how a runtime can project the canonical runtime dataset. They do not describe service behavior and do not create a runtime-specific dataset.
World may use a runtime capability declaration to include fallback state, degraded availability, or optional data that is already part of the canonical runtime dataset. World must not branch on runtime product name, and runtimes must not ask services for alternate runtime-specific contracts.
The current target capability classes are:
| Capability class | Typical capabilities | Runtime projection responsibility |
|---|---|---|
flat_viewport |
viewport_rendering, pointer_input |
Project workspace objects and contexts into a flat visual scene. Field objects may be listed when field projection is unsupported. |
camera_overlay |
camera_background, heading_sensor, field_projection, touch_input |
Project field objects relative to camera heading and render contexts in native controls. |
spatial_room |
spatial_anchors, field_projection, hand_tracking, volumetric_media |
Project objects into anchored or volumetric platform-native scene nodes. |
nonvisual |
audio_output, voice_input, linear_navigation |
Project workspace, context, field, and finding state into ordered prompts and command choices. |
The following dataset semantics are invariant across all projection classes:
- object ids, object types, source references, permissions, action references, relationships, placement anchors, and focus metadata;
- context ids, context items, action references, and targets;
- action ids, action types, World command URLs, controls, availability, and fallback policy;
- workspace item ids, focus order, active object, active context, and continuity state;
- field id, field object ids, world object references, locations, attribution, and fallback state;
- finding ids, source references, object types, titles, and action references.
A runtime may change scene construction, renderer-native layout, coordinate projection, input mapping, local focus presentation, and media realization. It must not change business meaning, infer permissions, create service routes, translate source references into direct service calls, or add Calendar, Social, Find, Maps, Messages, or other service business rules.
Unsupported capabilities are represented by fallbacks[] and action fallback
metadata. A runtime renders that explicit fallback data. It does not invent a
service-specific substitute. Unknown capabilities are ignored by older runtimes
and older World versions; unknown object, context, action, or field properties
are rendered generically or ignored according to fallback data.
The canonical projection class fixture is projection-capability-classes.json.
10. Compatibility field projection model
Each runtime projects field objects onto its display surface using bearing_degrees and distance_meters from the contract.
Web (panorama):
projectedX = ((bearing + 180) % 360) / 360 × fieldWidth
projectedY = clamp(120 + distance × 0.28, 84, 520)
Android / iPad (camera overlay):
relativeBearing = (bearing − deviceHeading + 360) % 360, folded to [−180, 180]
cull if |relativeBearing| > hFOV / 2
projectedX = (relativeBearing / hFOV + 0.5) × viewportWidth
projectedY = clamp(120 + distance × 0.28, 84, 520)
Category ids and control choices are contract data. A runtime never assumes a fixed category set.
The canonical examples and expected projection outputs are in Runtime Contract v2 Conformance Corpus.
The corpus also defines behavioral state transitions and exact World command requests for focus, order, placement, panels, authentication, and unavailable states. Runtime implementations must pass those scenarios without relying on Web code.
11. Compatibility surface stack gesture model
The gesture model is defined here as the platform standard. All runtimes implement these parameters using their platform's native rendering system.
- Drag threshold: 0.18 × viewport height to advance to the next surface
- Velocity threshold: ±650 pt/s (or platform-equivalent units) to trigger advance on release
- Tap detection: drag travel < 4% of viewport height with no qualifying velocity → focus that surface directly
Carry stack visual parameters:
- Offset per position step: 82 logical units
- Scale reduction per step: 0.10 per offset unit
- Minimum opacity: 0.34
Rail stack visual parameters:
- Offset per position step: 48 logical units
- Scale reduction per step: 0.06 per offset unit
- Minimum opacity: 0.42
The specific rendering mechanism (CSS transforms, Android Compose modifiers, SwiftUI geometry, etc.) is the runtime's responsibility. Only the numeric parameters are specified here.
12. Compatibility capability declaration
Every runtime must declare its capabilities when initiating a session. Capabilities are sent as a JSON-encoded X-Elonn-Runtime header on GET /world/session.
{
"runtime": "cardboard",
"version": "0.1.0",
"capabilities": {
"dock": true,
"surface_stacks": true,
"camera_background": true,
"field_markers": true,
"stereo_rendering": true,
"headset_mode": true
}
}
World may use declared capabilities to tailor the session response — for example, omitting field projection data for a runtime that declares no field support, or including richer spatial data for a runtime that declares geospatial anchors.
Runtime behavior must be capability-driven, not platform-name-driven. World must never branch on runtime name. If a behavior difference is needed, it must be expressed through a capability.
In the target architecture, the capability declaration informs World fallback state and lets runtimes decide how to project the canonical runtime dataset. The dataset itself must not become docks, stacks, rails, sheets, panels, markers, anchors, volumes, command groups, nonvisual prompts, or other renderer instructions.
Capabilities are open-ended. New hardware will introduce capabilities not listed here. Declare all supported capabilities; omit unsupported ones. Unknown capabilities are ignored by older World versions.
Current standard capabilities:
| Capability | Meaning |
|---|---|
dock |
Runtime renders ordered shell dock items |
surface_stacks |
Runtime renders ordered, focused surface stacks |
camera_background |
Runtime can render the field layer over a live camera feed |
field_markers |
Runtime renders field geo objects |
compass |
Runtime has access to a compass or equivalent heading source |
earth_anchors |
Runtime supports world-anchored object placement |
native_share |
Runtime exposes a platform-native share action |
offline_cache |
Runtime supports offline operation with cached data |
stereo_rendering |
Runtime renders split-screen stereoscopic output (e.g. VR headset) |
headset_mode |
Runtime is used inside a head-mounted display; touch interaction is unavailable or secondary |
gaze_input |
Runtime supports head-gaze as a pointing input — the heading vector is the cursor |
trigger_input |
Runtime has a single hardware confirm input (e.g. Cardboard magnetic trigger, controller trigger) |
pointer_input |
Runtime has a continuous pointer device (Bluetooth mouse or controller stick used as raycast cursor) |
13. Development environment
Every runtime must support configurable World and login endpoints. Production endpoints must be replaceable with alternate deployment endpoints at build or launch time without code changes.
This allows a runtime to be developed and tested against the deployment target used by the project without code changes. The deployment environment provides real data structures, real auth, and real service behavior — no fake datasets.
A runtime is not considered buildable until it can authenticate and load a session against the configured deployment target.
13. Compatibility implementation checklist
Build in this order:
- Runtime config: environment-selectable World base URL, login URL, runtime id, version, and capabilities.
- Auth: obtain
elonn_api_token, callGET /world/identity/me, handle 401 by showing login. - Session load: call
GET /world/sessionwithX-Elonn-Runtime, decodesurface_runtime,field_runtime, andservices. - Stack derivation: index surfaces by
surface_id, preserve every supported stack, and derive stack frames from each stack'ssurface_orderandfocused_surface_id. - Carry render: render focused carry surface, neighbor surfaces, left rail, right rail, top dock, and bottom dock without dropping surfaces by service id or URL.
- Focus writes: on carry focus, update local focus and
POST {surface_id}tosurface_runtime.commands.focus_surface. - Panel loading: when focused surface has
content_source.kind = runtime_panel, fetchcontent_source.url, rendernav,sections, andactions, and keep the panel transient unless World also supplies a durable surface record. - Workspace switching: implement carry, field, and find modes without changing service state.
- Field render: render
field_runtime.controls[], dispatch attached actions, refresh through World, and project returnedfield_runtime.objects[]. - Find: submit
POST /world/find/query, replace localsurface_runtimewith the returned one, renderfinding_overlayabove field and behind panels, show count/status, and clear only through World-provided actions. - Translation: open an
html_resourcethroughtranslate_surface, replace runtime state, and render its Surface Object without browser behavior. - Place open: open a
placefinding throughopen_finding, render the returnedmap_surfacein the center stack with marker and attribution, and preserve place details if map assets fail. - Placement writes: for movable/detachable surfaces, post placement changes to the URL from
update_placementafter replacing{surface_id}. - Error states: implement the error handling table exactly enough that no failed request leaves a blank or crashed region.
- Local verification: submit web and place queries, translate a web result, open a place result, refresh, and confirm the durable surfaces reload from World.
14. Compatibility acceptance criteria
A runtime passes runtime contract acceptance when all of these are true:
- It can run against local and production World endpoints by configuration only.
- It can be implemented from the Runtime Contract and contract examples without reading existing runtime or service code for hidden behavior.
- It consumes the shared Runtime Dataset v1 conformance corpus as first-class test input and passes every fixture/scenario relevant to its declared capabilities. Existing runtimes may also use Runtime Contract v2 fixtures as migration tests.
- It never calls API, Social, Messages, Maps, Time, Surface, Find, or provider services directly after token acquisition.
- It sends
X-Elonn-RuntimeonGET /world/session. - It renders exactly the surfaces supplied by
surface_runtime; it does not synthesize carry surfaces when a stack is empty. - It preserves every supported World-supplied stack, including
finding_overlay, and keeps carry focus independent of left/right context surfaces. - It derives stack focus from
surface_runtime.stacks[].focused_surface_id, not from whether a panel payload happened to load. - It renders dock items only from
shell.dock.items[]and does not hardcode dock membership, labels, icons, or order. - It renders canonical right rail content from the active
right_contextsurface, not from runtime-inferred service panel nav, and does not exposeright_context.surface_orderas service switching UI. - It renders a title bar and show/hide content control for every surface, and hiding content keeps the title bar visible.
- It keeps Field markers and detached findings behind panels and does not clear them when panels are hidden or workspaces change.
- It loads panels only from World URLs supplied by
content_source.urland keeps panel chrome separate from durable surfaces. - It keys panel payloads to the durable surface or modal that requested them and never uses panel payload data as durable surface identity.
- It renders full panel payloads with
title,summary,nav,sections, andactions, including empty and error states. Compact rail presentation uses the right rail contract above: surface title as chrome, panel items and action descriptors as controls, and summary only where the runtime has a non-primary presentation affordance such as a tooltip or detail view. - It refreshes the current panel after successful panel actions and form submissions, while preserving the current panel on inline validation errors.
- It submits find queries only to
/world/find/queryand renders returnedfinding_surfaceobjects fromsurface_runtime. - It translates web resources only through the supplied World command and renders normalized Surface Objects.
- It opens place findings only through the supplied World command and renders the resulting durable center-stack map surface with visible attribution.
- It never renders arbitrary source HTML, executes source JavaScript, or navigates to source URLs.
- It projects field objects from
field_runtime.objects[]without calling Maps. - It routes focus, reorder, and placement writes through
surface_runtime.commands. - It handles 401, failed load, failed panel load, failed find query, and failed form submit without crashing or showing a blank primary region.
- It preserves member scoping by never sending or storing another member id in runtime requests.
- It has a documented runtime id, version, capability set, local endpoint configuration, and manual test path.