# Message Text Pipeline & Markdown Rendering — Research ## Context Investigating why markdown formatting may appear as plain text in certain UI surfaces. --- ## 1. Full Text Pipeline: MessageComposer -> Inbox -> ActivityItem ### Step-by-step flow ``` MessageComposer.tsx (renderer) |-- User types into MentionableTextarea (plain text + chip tokens) |-- On send: serializeChipsWithText(text, chips) converts chip tokens to markdown fences |-- Calls onSend(recipient, serialized, serialized, attachments?) | teamSlice.ts (renderer store) |-- sendTeamMessage() -> api.teams.sendMessage(teamName, request) | TeamInboxWriter.ts (main process) |-- Writes InboxMessage to JSON file at teams/{teamName}/inboxes/{member}.json |-- `text` field stored verbatim — NO sanitization, NO escaping |-- JSON.stringify with null,2 (pretty-print) — safe for any string content | FileWatcher detects change -> store loads inbox data | ActivityItem.tsx (renderer) |-- stripAgentBlocks(message.text) removes ```info_for_agent``` blocks |-- linkifyTaskIdsInMarkdown() converts #123 to [#123](task://123) |-- Passes result to ``` ### Conclusion: Markdown IS preserved end-to-end The text field is stored as-is in JSON. No sanitization or escaping strips markdown formatting. `serializeChipsWithText()` even enriches plain text with markdown code fences for code chips. --- ## 2. TaskDetailDialog Description Rendering ### Current implementation (TaskDetailDialog.tsx, lines 539-566) **Read mode (not editing):** ```tsx ``` **Edit preview mode (lines 494-501):** ```tsx ``` ### Conclusion: TaskDetailDialog DOES use MarkdownViewer The description is rendered with `` in read mode. Markdown should render correctly here. If it appears as plain text, the issue is upstream — the description content itself may not contain markdown formatting (e.g., the task was created with plain text by CLI tooling, not from the UI). --- ## 3. Sanitization/Escaping Analysis | Layer | Sanitization | Impact on Markdown | |-------|-------------|-------------------| | `serializeChipsWithText()` | Replaces chip tokens with markdown — additive | **None** (enriches) | | `TeamInboxWriter.sendMessage()` | None — stores `request.text` verbatim | **None** | | `JSON.stringify/parse` | Standard JSON encoding | **None** (reversible) | | `stripAgentBlocks()` | Removes ````info_for_agent``` blocks only | **None** (targeted) | | `linkifyTaskIdsInMarkdown()` | Converts `#123` to `[#123](task://123)` | **None** (additive) | | `ReactMarkdown` | Parses markdown to HTML | **This IS the rendering** | **No layer strips or escapes markdown formatting.** The pipeline is clean. --- ## 4. Effect of MarkdownViewer `bare` Prop From `MarkdownViewer.tsx` (lines 561-571): ```tsx
``` **`bare` only affects the wrapper div styling:** - `bare={true}`: No background, no border, no shadow — for embedding inside cards. - `bare={false}` (default): Adds `CODE_BG` background, `CODE_BORDER` border, `rounded-lg shadow-sm`. **`bare` does NOT affect markdown parsing or rendering.** The same `ReactMarkdown` component with `remarkGfm` and `rehype-highlight` is used regardless. --- ## 5. Where Markdown Might Appear as Plain Text ### Identified scenarios 1. **Task descriptions from task tooling / Claude agents** Historically this included `teamctl.js`; the current architecture uses controller/MCP-based task operations. In both cases, agents typically write plain text descriptions, not markdown. The description content itself lacks formatting — MarkdownViewer renders it correctly, but there's nothing to format. 2. **Task comments from agents** Same issue — `task comment --text "..."` passes plain text. However, TaskCommentsSection.tsx (line 246) correctly uses ``. 3. **Structured JSON messages in ActivityItem** When `parseStructuredAgentMessage()` returns a match, the structured path renders `autoSummary` as a `

` tag and shows raw JSON in a `

` block — no MarkdownViewer. This is intentional for JSON protocol messages. 4. **Summary text in ActivityItem header** Line 375-377: `summaryText` is rendered as plain `` in the header row. This is by design — summaries are short single-line previews. 5. **ReplyQuoteBlock path in ActivityItem** When `parsedReply` is detected, it renders `` instead of MarkdownViewer. The quote block may not support full markdown — worth checking. ### NOT an issue - Description in TaskDetailDialog: correctly uses MarkdownViewer. - Activity feed messages: correctly uses MarkdownViewer for displayText. - Task comments: correctly uses MarkdownViewer. --- ## 6. Proposed Fixes ### Fix 1: No code change needed for the rendering pipeline The pipeline is correct. All text display surfaces that show long-form content already use MarkdownViewer. ### Fix 2: If specific content appears unformatted, the fix is upstream Ensure that agents/tooling that create tasks or comments use markdown formatting in their text. In the current architecture, this guidance applies to controller/MCP-backed task creation rather than the removed `teamctl.js` CLI. ### Fix 3 (Optional): ReplyQuoteBlock markdown support `ReplyQuoteBlock` renders the reply body. If it currently shows plain text, wrap body content in `` for consistency. (Needs verification — separate from this research scope.) --- ## Summary | Question | Answer | |----------|--------| | Is markdown preserved in the pipeline? | Yes — no sanitization strips it | | Does TaskDetailDialog use MarkdownViewer? | Yes — both read mode and edit preview | | Does any escaping strip formatting? | No — all transformations are additive or targeted | | Does `bare` affect rendering? | No — only wrapper styling (bg/border/shadow) | | Why might text appear unformatted? | Source content (from agents/CLI) is plain text, not markdown |