Add Copy Draft, Markdown, and Word export for Gary's AI outputs

✅ merged · #1 · zgbrenner/gary ← zgbrenner/gary · opened 7d ago by zgbrenner · merged 7d ago by zgbrenner · self · +1,211-40 across 7 files · ↗ on GitHub

From the PR description

Summary

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 a paste into Word preserves headings and bullets. Plain‑English status message: "Draft copied. Review before using."
  • Download Markdown - saves a .md file with a safe filename like contract-review-draft-2026-05-19.md, wrapped with a short title block (matter name, Saved Legal Task name, generated date) and an attorney‑review reminder.
  • Download Word Draft - saves a .docx via the already‑installed docx package; preserves headings, paragraphs, bullets, and simple GFM tables; ends with the short footer "Draft generated by Gary for attorney review."

Buttons appear under every non‑streaming assistant message in 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. Attorney‑review framing is preserved in every export.

Files changed

  • frontend/src/lib/exportDraft.ts (new) - pure helpers: sanitizeFilenamePart, buildFilename, buildMarkdownHeader, wrapDraftAsMarkdown, copyDraftToClipboard, downloadDraftAsMarkdown, downloadDraftAsDocx, markdownToBasicHtml. The DOCX path uses a small Markdown → docx converter so we don't pull in extra deps.
  • frontend/src/lib/exportDraft.test.ts (new) - focused tests for filename safety, header content, attorney‑review reminder, no API‑key/internal‑ID leakage, and clipboard failure messaging.
  • frontend/src/app/components/assistant/AssistantMessage.tsx - replaces the icon‑only copy button with the Copy Draft / Download Markdown / Download Word Draft action row plus a polite status line.
  • frontend/src/app/components/assistant/ChatView.tsx - threads optional matterName through and derives taskTitle from the preceding user message's workflow.
  • frontend/src/app/(pages)/projects/[id]/assistant/chat/[chatId]/page.tsx - same wiring inside the per‑matter chat, with project?.name as matterName.
  • docs/US_LAWYER_SETUP_GUIDE.md - new "Copying or Downloading Drafts" section explaining each action and the review checklist.
  • docs/US_TERMINOLOGY_MAP.md - added Copy Draft / Download Markdown / Download Word Draft / "Draft for attorney review" entries.

Attorney‑review framing

Every exported draft (Markdown and Word) starts with:

Attorney Review Required: Draft for attorney review. Do not rely on this output without verifying the facts, law, citations, and strategy.

DOCX exports also end with a centered italic footer: "Draft generated by Gary for attorney review."

Tests

  • bun run frontend/src/lib/exportDraft.test.ts - 11/11 pass. Covers safe filenames, header text, attorney‑review line, no leakage of sk-, api_key, bearer, document_id, version_id, edit_id, supabase, etc., no Workflow Template legacy wording, and a friendly fallback when clipboard isn't available.
  • bun run frontend/src/app/components/workflows/builtinWorkflows.test.ts - still passes.

Validation

  • Backend: bun run build - clean.
  • Frontend: bun run build - TypeScript compilation succeeds (Finished TypeScript in 14.0s). The build then fails during Next.js static prerendering of /account/models with Error: supabaseUrl is required. - that's the expected codespace failure mode because no Supabase env vars are configured here, and is unrelated to these changes.
  • Frontend: bun run lint - same number of errors before and after the change (43); the new files contribute zero new lint errors or warnings.

What was deferred

  • A formal template editor - kept the format labels (General Draft, Legal Memo, Demand Letter, Review Checklist, Chronology) as an internal DraftFormat enum on the helpers, but didn't surface a picker UI yet; the goal was to keep this PR focused.
  • Saving exports back into the matter as documents - out of scope; lawyers can re‑upload if they want a copy stored.

Test plan

  • Run a Saved Legal Task (e.g. Contract Review) on a sample document and confirm the three buttons appear under the response.
  • Copy Draft → paste into Word; confirm headings, bullets, bold survive and the attorney‑review reminder is present.
  • Download Markdown → confirm filename matches <matter>-<task>-draft-YYYY-MM-DD.md and contents include the header block.
  • Download Word Draft → open in Microsoft Word; confirm the title, attorney‑review reminder, body, and footer note render.
  • Try the actions on a chat with no matter (standalone) and confirm the header gracefully omits the Matter line.
  • Confirm the failure copy reads sensibly if you simulate clipboard denial in DevTools.

https://claude.ai/code/session_01LNzU9cGoR4SsYXon8H7aJZ


Generated by Claude Code

Our analysis

Add Copy, Markdown, and Word export actions to Gary's assistant responses — read the full analysis →

Think the analysis missed something the PR description covers?

Commits in this PR (2)

SHA Subject Author Date
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 PR into my fork

Download a Markdown prompt that tells Claude how to port every commit in this PR into your working tree. Run it via claude -p < capture-pull-1.md from inside the repo you want the changes in.

⬇ Download capture-pull-1.md