- Structured
mediaUrl/mediaUrlsfields for attachment delivery. [[audio_as_voice]]for audio presentation hints.[[reply_to_current]]/[[reply_to:<id>]]for reply metadata.[embed ...]for Control UI rich rendering.
[[...]] tags are delivery metadata. [embed ...] is the separate web-only rich-render path; it is not a media alias.
Media attachments
Remote attachments must be publichttps: URLs. http:, loopback, link-local, private, and internal hostnames are rejected as attachment directives; server-side media fetchers apply their own network guards on top.
Local attachments accept absolute paths, workspace-relative paths, or home-relative ~/ paths. They still pass the agent file-read policy and media type checks before delivery.
In Control UI chat, relative local references resolve against the session’s working directory, including a selected project or worktree. They use the same authenticated media route as absolute paths; a missing file shows an attachment error instead of a literal MEDIA: line. Files on another execution host must first be delivered as managed attachments.
Legacy MEDIA: lines
In automatic visible-reply mode, final assistant replies can still attach media
with a plain standalone MEDIA: line. WebChat also supports the committed
commentary compatibility path described below. The parser only recognizes lines
whose trimmed text starts with MEDIA: outside Markdown wrappers and fenced or
indented code blocks. Up to three leading spaces are accepted; four-space or tab
indentation follows CommonMark code-block rules.
Valid automatic-mode assistant output:
MEDIA:"https://example.com/video.mp4?token=ends,". The punctuation
stays part of the reference; attachment validation still applies.
WebChat commentary compatibility
In automatic mode, WebChat can also attach media from model-authored commentary (progress messages) once the assistant message is committed to the transcript, while the task continues. This is not parsing of arbitrary streaming deltas or streamed block payloads. The runtime captures the model-authored references beforebefore_message_write
hooks run. Only references from that captured set that remain in the committed
commentary are eligible for attachment preparation; references newly inserted by
a hook remain ordinary text. Preparation is bound to the exact committed message
and current admitted run. Captured references establish delivery intent, not file
access authority: file-read policy, media validation, authenticated serving, and
live run/session ownership checks still apply.
This compatibility does not replace message-tool-only delivery. When the resolved
source reply mode is message_tool_only (configured with
messages.visibleReplies: "message_tool"), visible output must use
message(action=send) and its structured attachment fields, not legacy MEDIA:
lines in commentary or final text. See visible reply configuration.
Structured payloads and block streaming
Tools, plugins, browser output, message actions, and streamed block payloads still require structured attachment fields as described above. Committed WebChat commentary is a separate compatibility path, not an exception for text returned by those producers. Plain Markdown image syntax stays text by default. Channels that intentionally map Markdown image replies to media attachments opt in at their outbound adapter; Telegram does this so can still become a media reply.
When block streaming is enabled, media in streamed blocks must ride on structured mediaUrl / mediaUrls fields. If the same media URL appears in a streamed block and again in the final assistant payload, OpenClaw delivers it once and strips the duplicate from the final payload.
[embed ...]
[embed ...] is the only agent-facing rich-render syntax for the Control UI. Self-closing example:
[view ...]is not valid for new output.[embed ...]replaced it in 2026.4.11 (#64104).- Embed shortcodes render only in the assistant message surface.
- Only URL-backed embeds render; use
ref="..."orurl="...". - Block-form inline HTML embed shortcodes do not render.
- The web UI strips the shortcode from visible text and renders the embed inline.
Stored rendering shape
The normalized/stored assistant content block is a structuredcanvas item:
present_view is not recognized; stored/rendered rich blocks always use this canvas shape.
Related
- Hosted embeds - how the Control UI renders
[embed ...]and its iframe sandbox policy - Typebox