Message logo

Message

Community
henkisdabro
message

Create 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 messages, or when user mentions Gmail, Outlook, WhatsApp, "email to", "reply to", "draft an email", "write an email", "send a message". Do NOT use for reading emails, managing contacts, or calendar invitations.

Overview

Publisherhenkisdabro
Repositorywookstar-claude-plugins
Skill namemessage
Stars
88
Forks
12
Bundled files
26
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 26 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by henkisdabro on GitHub. Read the source before you install it.

Installation

Install the Message AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/henkisdabro/wookstar-claude-plugins.git /tmp/wookstar-claude-plugins
mkdir -p .claude/skills
cp -r /tmp/wookstar-claude-plugins/plugins/message/skills/message .claude/skills/message
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Message in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Message on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Message is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Message Drafts

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.

Flow

  1. Write the .fragment.md directly to data/writing/email_drafts/ in ONE Write tool call. Do NOT write the email body inline in your response before the Write call. Compose the draft mentally and write it straight to the file - the preview server renders it.
  2. After the Write tool returns, read the URL the hook wrote:
    bash
    cat "${CLAUDE_PROJECT_DIR}/.claude/.message-preview-url" 2>/dev/null
  3. Reply with only the preview URL and a one-line summary: Draft ready: email to Sam re invoice follow-up → http://127.0.0.1:XXXX

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.

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.

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).

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:

bash
python3 -c "
import json, sys
d = json.load(open('${CLAUDE_PROJECT_DIR}/.claude/.message-previews.json'))
print(d.get(sys.argv[1], 'not found'))
" "/absolute/path/to/draft.fragment.md"

Fallback - if hook is not firing

If the hook is not firing (e.g. skill used outside the plugin), run manually. On a fresh install or a new machine, run the preflight first - it resolves/installs bun, installs dependencies, self-tests the build, and prints the exact serve command (and fails loudly with the fix if the environment is missing something):

bash
bash ${CLAUDE_PLUGIN_ROOT}/skills/message/scripts/preflight.sh

Then serve (use bun if it is on PATH, otherwise $HOME/.bun/bin/bun - the preflight prints the resolved path):

bash
bun run ${CLAUDE_PLUGIN_ROOT}/skills/message/scripts/serve.ts /path/to/name.fragment.md

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.

Fragment format

Markdown with YAML frontmatter.

markdown
---
to: recipient@example.com
subject: Subject line
cc: optional
bcc: optional
---

Body content in Markdown. Supports bold, italic, ~~strikethrough~~, headings, lists, blockquotes, code, tables, links. Embed raw HTML where Markdown falls short.

Required: to, subject. Do not use horizontal rules - they render poorly in email clients.

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 adds no blank line around lists (Gmail's own paste margins provide the gap) while the Rich Text lane does; the WhatsApp lane keeps code-block fences flush against neighbouring text. See references/formatting-rules.md, outlook-formatting.md and whatsapp-formatting.md for the per-lane rules.

Note: em and en dashes in the subject or body fail the build by design (house style: use " - " instead). The preview shows the exact error; replace the dash and it hot-reloads.

Tables - mandatory rules

When using tables, ALWAYS provide meaningful header names in the first row. Markdown's pipe-table syntax accepts blank headers (| | |) but the rendered output then shows a styled header row with no labels.

GOOD:

markdown
| Item | Amount |
|---|--:|
| Salary | $1,000.00 |

BAD - blank header row:

markdown
| | |
|---|--:|
| Salary | $1,000.00 |

If a table truly has no natural header, use descriptive labels like Item / Amount, Field / Value, Category / Notes. Header cells render with a light grey background (#f5f5f5) by default in both email lanes to differentiate them from data rows.

File naming

data/writing/email_drafts/YYYY-MM-DD_recipient_subject.fragment.md
data/writing/email_drafts/YYYY-MM-DD_recipient_subject.html        # generated

The hook fires on any *.fragment.md wherever it lives, so projects that keep drafts elsewhere work too - the path above is the recommended convention.

Preview UI

The browser preview shows three destination lanes - Gmail / Mail app / WhatsApp - each with a step-1 Copy button and a step-2 Open ↗ button. Internally they are still keyed gmail / outlook / whatsapp (wired to the build). The single visible body preview is the Rich Text rendering; the Gmail body stays off-screen so its copy payload remains faithful. Keyboard shortcuts:

  • G / T / M - copy for Gmail / copy Rich Text / copy Markdown
  • E / W - open default mail app / open WhatsApp
  • R - manual reload

Open ↗ buttons launch the system default apps. Each Open action POSTs to the preview server's /open endpoint, which hands the URL to the OS (open / xdg-open / cmd start) - so Gmail compose, the mail app, and WhatsApp open in the user's real browser/apps even when the preview page itself is viewed inside an embedded webview (VS Code / Zed in-app browsers, terminal-app browser panes). The endpoint allowlists only the four destination URL forms (scripts/open-url.ts); if the page is opened as a static file with no server, the buttons fall back to in-page window.open.

Features: dark-mode aware, live WebSocket hot reload (typically <100 ms; atomic-save editors reload via a 300 ms mtime poll), tooltips on every button, mobile-responsive, copy buttons use the Clipboard API's HTML MIME type so paste into Gmail/Outlook/Thunderbird preserves formatting as a single clean operation. The Rich Text lane (the old "Outlook" transform) is inline-styled HTML that pastes cleanly into any desktop mail client, not just Outlook. Build errors render as a red overlay with the exact message instead of a silent failure.

WhatsApp tables

Copy Markdown renders any table in the message as a fenced ``` code block with columns padded to equal width, so it reads as an aligned grid in WhatsApp's monospace rendering; the Gmail and Rich Text lanes keep the real HTML table. Keep WhatsApp-bound tables to 3-4 lean columns. Mechanics and limits: references/whatsapp-formatting.md.

Edit flow

Edit the .fragment.md file. The running server detects the change (fs.watch fast path, plus a 300 ms mtime poll that catches the atomic write+rename saves fs.watch silently drops on macOS) and pushes a reload over WebSocket. No manual refresh. Latency from save to visible update: typically under 100 ms, up to ~400 ms for atomic-save editors.

Env flags

  • MESSAGE_NO_OPEN=1 - skip auto-opening the browser (useful in headless contexts)

Date and day-of-week accuracy

Any fragment that names a specific date, a day of week, or a relative time ("this Thursday", "next week", "the 15th", "COB Friday", "tomorrow", "end of the month") MUST be verified with a python3 datetime run BEFORE the draft is finalised - never rely on mental arithmetic. Confirm the weekday matches the calendar date, that any relative reference resolves to the intended absolute date, and that the date is not unintentionally in the past. Anchor relative references to today's date (in the environment context).

bash
python3 -c "import datetime; d=datetime.date(2026,7,17); print(d.strftime('%A %d %B %Y'))"

If the check contradicts the draft (e.g. it says "Thursday the 15th" but the 15th is a Wednesday), fix the fragment and re-verify. The preview hot-reloads, so correcting the date in the fragment updates the preview immediately.

Structure and tone

  1. Lead with the point (request, update, instruction the recipient must act on)
  2. Supporting detail (context, logistics)
  3. Warm close (gratitude, relational content) just before the sign-off

Match the recipient's formality.

Your defaults

Customise these for the user's context:

  • From / reply-to: your-email@example.com
  • Sign-off: Best,\n[Your Name]

After preview

Once the user has the preview URL, ask: "Would you like me to run the humanise skill on this draft to make it sound more natural?"

Post-draft actions

After a client-facing draft, prompt the user if they'd like to log this to a comms log or trigger any downstream actions in their project.

References

Maintainer-only - do NOT load while drafting. You write Markdown; the build script's transforms produce all the inline-styled HTML. Loading these mid-draft will mislead you into hand-writing raw HTML. They exist so a human can audit/adjust the transform output.

  • references/formatting-rules.md - Gmail native HTML the build transform emits
  • references/outlook-formatting.md - Outlook element styles and colour palette
  • references/whatsapp-formatting.md - WhatsApp text conversion and fixed-width table mechanics

Development

Code lives in ${CLAUDE_PLUGIN_ROOT}/skills/message/scripts/. First-time setup on any machine: bash scripts/preflight.sh - it installs bun + dependencies and self-tests, or fails loudly with the fix. Then bun commands work (fall back to $HOME/.bun/bin/bun if bun is not on PATH). Run tests: cd skills/message && bun test. Build-only without serving: bun run scripts/serve.ts <fragment> --build-only.

Platform support

Works on macOS, Linux, WSL2 (Ubuntu), and native Windows. The hook is auto-serve-fragment.ts and runs under Bun on all platforms - bun must be on PATH. Browser opening is handled by serve.ts itself: open on macOS, cmd /c start on Windows, cmd.exe /c start on WSL2 (opens the Windows host browser via shared localhost), xdg-open elsewhere. On minimal Linux setups without xdg-open handlers for mailto:/whatsapp://, the Open buttons may no-op - use the Copy buttons instead.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Message AI skill do?

Create 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 messages, or when user mentions Gmail, Outlook, WhatsApp, "email to", "reply to", "draft an email", "write an email", "send a message". Do NOT use for reading emails, managing contacts, or calendar invitations.

Why use Message on TypingMind?

Because you install it once and use it with any model. Message is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Message in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/henkisdabro/wookstar-claude-plugins/tree/main/plugins/message/skills/message. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Message?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Message?

As many as you like. As long as a model supports skills, you can use Message with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Message AI skill free?

It is published on GitHub by henkisdabro. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇