Appearance
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:
- The user types a slash command (
/files,/build,/diff,/project,/components,/inspector,/coding,/table-demo) —ChatApp.tsrecognizes the command and callschat.messages messages.add-component { tag, mount }. - The model emits a
messages.add-componentop via tool-call.system.agentsforwards the op back to Chat through theactivityToaddress; Chat dispatches it intochat-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
| Tag | Class | What it renders |
|---|---|---|
mx-chat-message | MxChatMessage | A single message bubble. Used for user, assistant, system, and error roles. |
mx-markdown-viewer | MxMarkdownViewer | Markdown with KaTeX, mermaid, and highlight.js code blocks. |
mx-code-viewer | MxCodeViewer | Highlighted code block actor (single language). |
mx-data-table | MxDataTable | Sortable / interactive data table — table.setData, table.sortBy, table.getData. |
mx-component-browser | MxComponentBrowser | Browse and pick components to embed. |
mx-activity-trace | MxActivityTraceActor | Render $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:
| Command | Action | Typical component |
|---|---|---|
/components | show-components | mx-component-browser |
/inspector | show-inspector | (target's introspect view) |
/project | show-project | (project files actor) |
/build | show-build | (build status actor) |
/files | show-files | (file tree actor) |
/coding | show-coding | (coding workbench actor) |
/diff | show-diff | (diff viewer actor) |
/table-demo | run-table-demo | mx-data-table |
/retarget | retarget | (target picker; not an inline component) |
/theme | theme | (theme switcher) |
/export | export-chat | (export dialog) |
/help | show-help | (help message) |
/clear | clear-messages | (clears transcript) |
/sessions | show-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.