Three export actions below every Gary response: clipboard, Markdown, Word
zgbrenner added Copy Draft, Download Markdown, and Download Word Draft buttons beneath completed assistant responses. The feature ships with a 677-line export module, a 317-line test suite, and a deliberate design constraint: the wrapper never redacts or scrubs AI content, but also never injects credential-shaped tokens into the exported file.
The three actions appeared in b4345deb and were refined in 347a4240. Copy Draft writes both an HTML payload and a Markdown payload to the clipboard simultaneously, so pasting into Word preserves headings and bullet structure without a format-conversion step. Download Markdown generates a .md file with a dated, slug-sanitized filename like contract-review-draft-2026-05-19.md, opening with a header block that names the matter, task, and date alongside an attorney-review reminder. Download Word Draft runs the Markdown through a converter using the docx package already in the project - headings, paragraphs, bullets, and simple GFM tables survive the conversion.
The core logic lives in frontend/src/lib/exportDraft.ts. The module is pure helpers: filename sanitization, header construction, a Markdown wrapper, the clipboard write, and the Markdown-to-docx converter. It's shared between the standalone assistant chat and the per-matter chat view; the per-matter chat threads the matter name and the derived task title through so exported files carry context.
347a4240 added two refinements. The export row now hides on replies under 200 characters - the threshold is documented as deliberately conservative, preferring false positives (showing buttons on borderline short answers) over false negatives (hiding them on a real one-paragraph memo). The no-scrub invariant was also made explicit: wrapDraftAsMarkdown preserves AI content verbatim. A test confirms that legal analysis mentioning "API key" or "Bearer token" (legitimate contract language) survives unchanged. The credential-leak tests check the wrapper's own additions, not the AI's prose.
The action row renders only after streaming completes. Task title lookup walks back through the message array to find the most recent prior user message that carried a workflow title, so exports from per-matter chats correctly identify which Saved Legal Task generated the response.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?