Skip to content

Files and artifacts

Chat can render inline components inside the transcript. They show up as block elements between messages and behave like regular Matrix actors — bus-addressable, op-driven, mountable on chat.messages.

How an inline component appears

Either:

  1. The user types a slash command (/files, /build, /diff, /project, /components, /inspector, /coding, /table-demo) — ChatApp.ts recognizes the command and calls chat.messages messages.add-component { tag, mount }.
  2. The model emits a messages.add-component op via tool-call. system.agents forwards the op back to Chat through the activityTo address; Chat dispatches it into chat-message-list.

The new component mounts under chat.messages.<componentMount> (e.g., chat.messages.editor). It's a real actor with its own inbox.

Built-in renderers

TagClassWhat it renders
mx-chat-messageMxChatMessageA single message bubble. Used for user, assistant, system, and error roles.
mx-markdown-viewerMxMarkdownViewerMarkdown with KaTeX, mermaid, and highlight.js code blocks.
mx-code-viewerMxCodeViewerHighlighted code block actor (single language).
mx-data-tableMxDataTableSortable / interactive data table — table.setData, table.sortBy, table.getData.
mx-component-browserMxComponentBrowserBrowse and pick components to embed.
mx-activity-traceMxActivityTraceActorRender $activity frame stream as an ops trace.

These are all MatrixActorHtmlElements. They obey the same composition rules as the rest of Chat.

Slash command → component map

From ChatApp.ts:131-146:

CommandActionTypical component
/componentsshow-componentsmx-component-browser
/inspectorshow-inspector(target's introspect view)
/projectshow-project(project files actor)
/buildshow-build(build status actor)
/filesshow-files(file tree actor)
/codingshow-coding(coding workbench actor)
/diffshow-diff(diff viewer actor)
/table-demorun-table-demomx-data-table
/retargetretarget(target picker; not an inline component)
/themetheme(theme switcher)
/exportexport-chat(export dialog)
/helpshow-help(help message)
/clearclear-messages(clears transcript)
/sessionsshow-sessions(session list)

The exact actor mounted depends on which packages are present in the runtime — Chat doesn't ship mx-files, mx-build, etc. itself. They come from companion packages, and the slash command is a no-op if the actor isn't reachable.

Persistence

config.state.persistInlineComponents (default true) determines whether inline components are written into session_state.transcript. With persistence on, resuming a session re-renders the inline components.

Each component declares a __mxResumeSourceHash so Chat knows whether the resumed source matches the registered class — if a component's source changed since the session was saved, Chat reconstructs from the saved spec.

Manual mount via op

A page or actor with bus access can drive an inline component without a slash command:

bash
matrix invoke chat.messages messages.add-component \
  '{"tag":"mx-data-table","mount":"my-table"}'

matrix invoke chat.messages.my-table table.setData \
  '{"label":"Rows","data":[{"name":"A","score":1},{"name":"B","score":3}]}'

That's how runTableDemo() (ChatApp.ts:3213-3287) drives the /table-demo command.

Exports

The export service writes the transcript including inline components. Markdown export serializes inline tables as Markdown tables; code blocks as fenced blocks; markdown bodies inline. JSON export preserves the full record store including component manifests so a transcript can be replayed in another Chat instance.

See also

Source: projects/matrix-3/packages/chat/src/ChatApp.ts:131-146 (slash table), :3205-3287 (component activation, table demo), src/elements/ (renderer classes), src/components/ChatMessageList.ts.