$npx -y skills add henkisdabro/wookstar-claude-plugins --skill messageCreate and edit rich text message drafts for Gmail, Outlook, and WhatsApp with live browser preview. Runs on Bun for near-instant cold start and opens the preview automatically. Use when writing emails, drafting emails, composing replies, sending messages, writing WhatsApp messag
| 1 | # Message Drafts |
| 2 | |
| 3 | Bun-based preview server. Fragments are written in Markdown - the build script converts to platform-specific HTML. The plugin's PostToolUse hook (`hooks/auto-serve-fragment.ts`, registered in this file's frontmatter on the `Write|Edit|MultiEdit` matcher) auto-builds, starts the preview server, and opens the browser whenever a `.fragment.md` is written or edited. |
| 4 | |
| 5 | ## Flow |
| 6 | |
| 7 | 1. Write the `.fragment.md` directly to `data/writing/email_drafts/` in ONE Write tool call. |
| 8 | **Do NOT write the email body inline in your response before the Write call.** Compose the |
| 9 | draft mentally and write it straight to the file - the preview server renders it. |
| 10 | 2. After the Write tool returns, read the URL the hook wrote: |
| 11 | ```bash |
| 12 | cat "${CLAUDE_PROJECT_DIR}/.claude/.message-preview-url" 2>/dev/null |
| 13 | ``` |
| 14 | 3. Reply with only the preview URL and a one-line summary: |
| 15 | `Draft ready: email to Sam re invoice follow-up → http://127.0.0.1:XXXX` |
| 16 | |
| 17 | **The hook has already started the server and opened the browser by the time the Write tool returns.** Do NOT run `bun run serve.ts` yourself. Do NOT call `open <url>`. Do NOT launch a second server. The browser is already open. |
| 18 | |
| 19 | **Always relay the preview URL to the user.** Read it from `.claude/.message-preview-url`. If that file is empty or missing, the hook did not start a server - run the manual **Fallback** below rather than guessing at a URL. |
| 20 | |
| 21 | **On revision** ("make it shorter", "change the tone"): use Read to load the fragment, Edit to apply changes. The running server hot-reloads over WebSocket (typically <100 ms; up to ~400 ms for editors that save atomically, which reload via the mtime poll). Do not echo the revised body - just confirm the change and include the same URL. Do NOT start a new server - the existing one is still running (and the `Edit` matcher on the hook will resurrect one if it had shut down). |
| 22 | |
| 23 | **Multiple concurrent drafts** are fully supported. Each fragment gets its own server on its own port. A server stays alive while a preview tab is connected to it; with no connected tab it idle-shuts-down after 30 minutes (re-writing/editing the fragment starts a fresh one via the hook). To find the URL for any previously opened draft, run: |
| 24 | |
| 25 | ```bash |
| 26 | python3 -c " |
| 27 | import json, sys |
| 28 | d = json.load(open('${CLAUDE_PROJECT_DIR}/.claude/.message-previews.json')) |
| 29 | print(d.get(sys.argv[1], 'not found')) |
| 30 | " "/absolute/path/to/draft.fragment.md" |
| 31 | ``` |
| 32 | |
| 33 | ## Fallback - if hook is not firing |
| 34 | |
| 35 | If the hook is not firing (e.g. skill used outside the plugin), run manually. |
| 36 | On a fresh install or a new machine, run the preflight first - it resolves/installs |
| 37 | bun, installs dependencies, self-tests the build, and prints the exact serve |
| 38 | command (and fails loudly with the fix if the environment is missing something): |
| 39 | |
| 40 | ```bash |
| 41 | bash ${CLAUDE_PLUGIN_ROOT}/skills/message/scripts/preflight.sh |
| 42 | ``` |
| 43 | |
| 44 | Then serve (use `bun` if it is on PATH, otherwise `$HOME/.bun/bin/bun` - the |
| 45 | preflight prints the resolved path): |
| 46 | |
| 47 | ```bash |
| 48 | bun run ${CLAUDE_PLUGIN_ROOT}/skills/message/scripts/serve.ts /path/to/name.fragment.md |
| 49 | ``` |
| 50 | |
| 51 | Run with `run_in_background: true`. The server prints the output HTML path then the URL. Relay the URL to the user. On subsequent edits, the server hot-reloads automatically - do not re-run it. |
| 52 | |
| 53 | ## Fragment format |
| 54 | |
| 55 | Markdown with YAML frontmatter. |
| 56 | |
| 57 | ```markdown |
| 58 | --- |
| 59 | to: recipient@example.com |
| 60 | subject: Subject line |
| 61 | cc: optional |
| 62 | bcc: optional |
| 63 | --- |
| 64 | |
| 65 | Body content in Markdown. Supports bold, italic, ~~strikethrough~~, headings, lists, blockquotes, code, tables, links. Embed raw HTML where Markdown falls short. |
| 66 | ``` |
| 67 | |
| 68 | Required: `to`, `subject`. Do not use horizontal rules - they render poorly in email clients. |
| 69 | |
| 70 | Line breaks: a single newline inside a paragraph is a real line break in every lane (`marked` runs with `breaks: true`), so write sign-offs as `Best,` newline `Alex` - no trailing-space tricks. Consequently, never hard-wrap prose; keep each paragraph on one source line. A blank line separates paragraphs and renders as one blank line in all lanes. Around other blocks the lanes differ deliberately: headings sit flush above their text in both email lanes; the Gmail lane |