Messages Contract
Messages are open one-to-one member communications outside Social context. Messages are not Social conversations, Social DMs, conversation replies, or event replies.
World exposes Messages to runtimes through /world/messages routes. Runtimes do not call producer services directly.
messages.elonn.local owns platform Messages. Social DMs remain in social.elonn.local.
Ownership
Messages owns:
- open message threads
- two thread participants
- message bodies
- inbox ordering
- unread/read state for message threads
- message-thread object sources
- message-thread runtime panel payloads as compatibility presentation content
Boundaries:
- Conversations, communities, social events, replies, and Social DMs belong to Social.
- Member identity and recipient lookup come from API through World.
- World owns composed object identity, effective permissions, relationships, placement, and runtime routing.
- Runtimes own panels, rails, markers, lists, meshes, interaction, and rendering.
- A message thread must have exactly two participants. If communication needs more than two members, the runtime must guide the member to create or use a Social community, conversation, or event.
Producer object route
World consumes Messages object sources from:
GET /messages/objects
Messages returns:
| Field | Type | Meaning |
|---|---|---|
objects.threads |
array | Message thread object sources |
This is the service-to-World route. It is not a runtime route. Runtimes do not call it.
Message thread object source
A message thread object source follows the object source contract.
| Field | Type | Meaning |
|---|---|---|
source.service |
string | messages |
source.resource_type |
string | thread |
source.resource_id |
string | Stable Messages thread id |
object_type |
string | message_thread |
title |
string | Thread title or participant label |
summary |
string | Latest-message preview or empty summary |
state.id |
string | Thread id |
state.current_identity_user_id |
string | Authenticated member identity id |
state.participants |
array | Thread participants visible to the authenticated member |
state.participant_count |
integer | Number of participants |
state.message_count |
integer | Number of messages in the thread |
state.unread_count |
integer | Messages newer than the member's read state |
state.last_message_at |
string | null |
state.created_at |
string | Thread creation timestamp |
state.updated_at |
string | null |
domain_permissions.can_view |
boolean | Member may view the thread |
domain_permissions.can_reply |
boolean | Member may send a message in the thread |
domain_permissions.can_add_participant |
boolean | Always false for Messages |
domain_actions |
array | open_thread and send_message semantic actions |
relationships |
array | Empty unless Messages owns a service-local relationship |
Messages object sources must not include panels, rails, docks, stacks, Surface ids, runtime URLs, or placement. World maps these object sources into canonical World objects and World-routed actions.
Runtime routes through World
Runtimes use only World URLs:
GET /world/messages
GET /world/messages/{id}
POST /world/messages
POST /world/messages/{id}/messages
GET /world/panels/messages
The legacy GET /world/messages and panel payloads remain available while runtimes move to translated World contracts.
Thread object
A message thread represents one open one-to-one member communication context outside Social.
| Field | Type | Meaning |
|---|---|---|
id |
integer | string |
type |
string | message_thread |
title |
string | Runtime display label |
summary |
string | Runtime summary text |
participants |
array | Thread participants visible to the authenticated member |
participant_count |
integer | Number of participants |
message_count |
integer | Number of messages in the thread |
unread_count |
integer | Messages newer than the member's read state |
last_message_at |
string | null |
created_at |
string | Thread creation timestamp |
updated_at |
string | null |
links.self |
string | /world/messages/{id} |
links.messages |
string | /world/messages/{id}/messages |
actions.open_thread |
string | /world/messages/{id} |
actions.send_message |
string | /world/messages/{id}/messages |
World may include additional diagnostic or implementation fields. Runtimes must ignore unknown fields.
Message object
| Field | Type | Meaning |
|---|---|---|
id |
integer | string |
thread_id |
integer | string |
sender_identity_user_id |
integer | string |
body |
string | Message body |
created_at |
string | Creation timestamp |
updated_at |
string | null |
Message bodies are private to thread participants. Runtimes must not expose message bodies outside the authenticated member's message surfaces.
Panel payload
GET /world/panels/messages is a compatibility endpoint for legacy runtimes
and compatibility surfaces that still need the older panel payload. New runtime
work should use translated World objects, translated actions, and direct World
thread routes.
The compatibility endpoint returns a runtime panel payload with:
| Field | Type | Meaning |
|---|---|---|
kind |
string | messages |
view |
string | messages |
title |
string | Panel title |
summary |
string | Panel summary |
threads |
array | Message thread objects |
selected_thread |
object | null |
messages |
array | Messages for the selected thread when present |
actions.start_thread |
string | /world/messages |
Writes
Start or reuse a thread:
POST /world/messages
Request body:
| Field | Type | Meaning |
|---|---|---|
recipient |
string | Member id, username, email, or display label resolved by World |
body |
string | Initial message body |
Returned JSON fields:
| Field | Type |
|---|---|
thread |
MessageThread |
message |
Message |
World forwards authenticated member context; runtimes must not submit another member id as the sender.
Append to a thread:
POST /world/messages/{id}/messages
Request body:
| Field | Type | Meaning |
|---|---|---|
body |
string | Message body |
Returned JSON fields:
| Field | Type |
|---|---|
thread |
MessageThread |
message |
Message |
Errors
| Status | Meaning |
|---|---|
400 |
Required field missing or empty |
401 |
Member is not authenticated |
403 |
Member cannot access the thread |
404 |
Thread or recipient not found |
422 |
Request is valid JSON/form data but cannot be applied; adding another participant must direct the member to create or use a Social community, conversation, or event |
5xx |
Messages unavailable |
Runtime rules
- New runtimes load Messages from translated World
message_threadobjects and translated action commands. - Legacy runtimes may load message panels from
content_source.urlor/world/panels/messageswhile compatibility remains available. - Current Web treats the Messages
content_source.urlas compatibility metadata and renders active Messages from translated World objects and actions. - World marks the Messages service and
surface_messagescontent_sourcepayloads withcompatibility: trueandcompatibility_scope: "legacy_runtime_panel"while the compatibility panel URL remains present. - World publishes Messages navigation/context through
/world/translatedcontexts[]items. These items reference translated thread objects and translated action ids; runtimes decide whether to render them as a right-side area, sidebar, palette, spatial control, or another interaction surface. - Runtimes open threads through translated
open_threadcommands,links.self, oractions.open_thread. - Runtimes send messages through translated
send_messagecommands,links.messages, oractions.send_message. - Current Web active Messages rendering resolves open/send routes from
actions.open_threadandactions.send_messageonly. Compatibility link fields may remain in payloads for older paths, but they are not Web fallbacks. - Current Web does not render directly from compatibility
selected_threadobjects. Compatibility panel delegation may pass selected thread identity, and Web resolves that identity against translated Worldmessage_threadobjects. - Current Web active Messages selection uses
selected_message_threadfor the translated workspace payload.selected_threadremains a legacy compatibility-panel key and is not the active Messages workspace contract. - Runtimes return from thread detail to the Messages thread list through
translated Messages workspace/context identity, not by testing for legacy
content_sourcemetadata. - Runtime-specific container identifiers, such as Web's current
surface_messagescenter-stack container, are adapter mappings for the translated Messages workspace. They are not service-owned Messages concepts. - Runtime adapters should keep those mappings centralized so workspace opening, service opening, dock active state, context, focus, content loading, and interaction helpers consume the same translated workspace descriptor instead of repeating container ids or workspace keys.
- Runtimes do not treat message threads as Social conversations or Social DMs.
- Runtimes do not route Messages through Social workspace selection state.
- Runtime adapters should not expose Social-owned markup, state, or form-status names from Messages renderers.
- Runtimes do not construct producer service URLs.
- Runtimes do not consume
GET /messages/objects; World consumes it and translates the result.