Isolated export module: clipboard, Markdown file, and Word doc from any chat response

`b4345deb` adds `frontend/src/lib/exportDraft.ts` - 677 lines of pure export helpers covering clipboard writes, filename sanitization, Markdown wrapping, and Markdown-to-docx conversion. A 317-line test suite ships alongside it. The module is shared by both chat views with no side effects on the chat state.

draftingworkflow

The three export paths work differently at the implementation level. Copy Draft calls navigator.clipboard.write with two clipboard items simultaneously: a text/html payload (converted from Markdown so Word receives structured content) and a text/plain Markdown payload as fallback. Download Markdown generates a safe slugified filename from the task title and current date, prepends a metadata header with matter name, task, date, and the attorney-review reminder, and triggers a blob download. Download Word Draft runs the Markdown through a converter that uses the docx package already in the project - headings map to HeadingLevel constants, bullets become numbered or bullet lists depending on GFM syntax, and simple tables are preserved.

The test suite in exportDraft.test.ts covers filename sanitization (including Unicode and special characters), header content, the no-scrub invariant, and credential-leak avoidance. The credential tests check the wrapper's additions only - the wrapper preserves AI content verbatim and a separate test confirms that legal prose mentioning "API key" or "Bearer token" survives unchanged.

347a4240 added a 200-character gating threshold. The export row renders only when the stripped export content is at least 200 characters long. The comment in the code is explicit: the threshold is conservative - it would rather show buttons on a borderline-short answer than hide them on a real memo. Short conversational replies ("Done.", "I need more information.") don't get the export row.

The per-matter chat threads task title lookup through a backward scan of the message array to find the most recent prior user message that carried a workflow title. That context is passed as taskTitle to the export functions so filenames and headers name the task correctly.

So what The strongest import candidate in this fork's run. `exportDraft.ts` is self-contained, adds no new dependencies beyond `docx` (which Gary already bundles), and ships with tests covering the cases that matter for a legal product. The 200-char gating and the explicit verbatim-preservation invariant are details that make it production-ready rather than a quick feature add. Adopt by reading the file directly and adapting the task-title threading to your own message schema.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

3 commits from zgbrenner/gary, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
cc41294b Merge pull request #1 from foolish-bandit/claude/gary-us-simplification-AjDDT Zack Brenner 2026-05-19 ↗ GitHub
Add Copy Draft, Markdown, and Word export for Gary's AI outputs
b4345deb feat: add Copy Draft, Markdown, and Word export for AI outputs Claude 2026-05-19 ↗ GitHub
commit body
Adds three export actions below every Gary assistant response so U.S.
lawyers can move drafts into Word, email, or their own templates in one
click:

- "Copy Draft" - clipboard copy with HTML + Markdown payloads so paste
  into Word preserves headings and bullets; plain-English status text.
- "Download Markdown" - `.md` file with safe filename like
  `contract-review-draft-2026-05-19.md`, wrapped with a short title
  block (matter, Saved Legal Task, date) and an attorney-review
  reminder.
- "Download Word Draft" - `.docx` via the already-installed `docx`
  package; preserves headings, paragraphs, bullets, and simple GFM
  tables; ends with a short footer note.

Helpers live in `frontend/src/lib/exportDraft.ts` and are reused by both
the standalone assistant chat and the per-matter chat. Exports include
only the assistant's prose - internal events, tool calls, IDs, and
annotations are intentionally excluded.

Adds focused tests in `exportDraft.test.ts` covering filename safety,
header content, attorney-review reminder, no API-key/internal-ID
leakage, and clipboard failure messaging.

Updates the U.S. lawyer setup guide with a "Copying or Downloading
Drafts" section, and extends the terminology map.
347a4240 fix: hide export row on very short replies; clarify no-scrub invariant Claude 2026-05-19 ↗ GitHub
commit body
- AssistantMessage: only render Copy Draft / Download Markdown /
  Download Word Draft when the assistant's prose is at least 200
  characters. Tiny conversational replies like "Done." or
  "I need more information." stay uncluttered.
- exportDraft: document explicitly that the wrapper preserves AI
  content verbatim and never scrubs or redacts. The invariant we
  guard is the inverse - nothing the wrapper adds should introduce
  credential-shaped tokens.
- exportDraft.test: add a positive test confirming that legitimate
  legal text discussing "API key" rotation or "Bearer token"
  authentication is preserved unchanged in the export.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-532.md from inside the repo you want the changes in.

⬇ Download capture-thread-532.md