| name | email-composer |
| description | Composes, drafts, and sends emails via Gmail. Enforces natural writing style (no em dashes, no AI tells), proper threading, and correct signature handling. Use whenever drafting, replying to, or sending any email. |
| argument-hint | [reply-to thread or new email subject] |
Email Composer
Purpose
Handle all email composition. Ensures emails read naturally, thread correctly, and preserve the user's Gmail signature.
Runtime Context
Before composing any email, retrieve the current user's profile via Supabase MCP execute_sql:
SELECT email, display_name, scheduling_link, domain, preferences
FROM user_profiles WHERE user_id = auth.uid()
Use these values throughout — never hardcode emails, names, or domains.
- Sender email: Use
email from user_profiles
- Scheduling link: Use
scheduling_link from user_profiles
- User's domain: Use
domain from user_profiles
- Display name: Use
display_name from user_profiles
- Supabase project ID: Read from
$SUPABASE_PROJECT_ID environment variable
When This Skill Activates
Any time the user asks to:
- Draft an email or reply
- Send an email
- Compose a message for someone
- Respond to an email thread
- Forward an email
Writing Style Rules
Absolute Prohibitions
These are dead giveaways that AI drafted the email. Never use them in email body text:
-
Em dashes (—) and en dashes (–). Rewrite using commas, periods, semicolons, or parentheses instead.
- BAD: "We've talked it through — and have some questions"
- GOOD: "We've talked it through and have some questions"
-
Hyphen-style bullet lists in the email body. Use numbered lists, line breaks, or prose paragraphs instead. If a list is truly needed, use plain numbers or letters.
-
Filler pleasantries: "I hope this email finds you well", "Please don't hesitate to reach out", "I wanted to touch base", "I'd be happy to assist"
-
Overly formal constructions: "Per our previous discussion", "As per your request", "Pursuant to", "In regard to"
-
AI hedging patterns: "It's worth noting that", "It's important to mention", "I should point out that"
Voice and Tone
Write in the user's voice:
- Direct and conversational. Write like you'd talk to a coworker.
- Concise. Get to the point quickly. Short paragraphs, short sentences.
- Warm but not fluffy. Friendly opener, clear ask, done.
- Use contractions naturally (we've, don't, I'll, that's).
- Lowercase "i" in casual internal emails is fine if it matches prior thread tone.
Scheduling a Meeting or Call
Scheduling link: Use the scheduling_link value from user_profiles whenever the user wants to include a link for the recipient to book a time.
When the email involves setting up a time to talk, close with a simple ask for availability. Keep it natural and conversational, e.g. "Let me know if any day this week works for you."
If specific times are being offered, list them and add a fallback like "If none of those work, let me know what's better."
Calendar "Hold" Blocks
Events titled just "Hold" (or similar generic holds without a specific name) are personal time blocks the user uses to prevent external bookings. They are NOT real commitments.
- "Hold" or "Hold - [time block reason]" with no person/company name → treat as available/free time
- "Hold for McArthy's", "Hold for Jordan", etc. with a specific name → treat as a real commitment, do NOT offer this time
When checking availability, read the full event list (not just freebusy) to distinguish between generic holds and named holds.
Structural Guidelines
- Lead with context or the ask, not preamble
- One topic per paragraph
- End with a clear next step or question
- Keep emails under 150 words when possible (exceptions: complex multi-point replies)
Signature Handling
The draft_gmail_message and send_gmail_message tools auto-append the Gmail signature via include_signature: true (the default). Do NOT manually fetch or embed the signature in the body -- this causes double signatures.
Just write the email body content and let the tool handle the signature.
Body Format
Use body_format: "html" for all emails so the signature renders correctly. Wrap paragraphs in <p> tags:
<div dir="ltr">
<p>[paragraph 1]</p>
<p>[paragraph 2]</p>
<p>[sign-off name]</p>
</div>
For Drafts
Full mode: Use the Google Workspace MCP draft_gmail_message tool with body_format: "html". The user will review and send from Gmail.
Quick mode: Use the built-in gmail_create_draft tool (discovered via ToolSearch: "+gmail draft"). Use contentType: "text/html". This tool does not auto-append a Gmail signature — append the user's sign-off name at the end of the body. The user adds their full signature when sending from Gmail.
For Programmatic Sends
Full mode only. Use the Google Workspace MCP send_gmail_message tool with body_format: "html". Only use programmatic send when the user explicitly says "send it" (not "draft it" or "save it").
Quick mode: Programmatic send is not available. Always create a draft and tell the user: "Draft created — open Gmail to review and send." If the user says "send it", explain that quick mode only supports drafts and suggest switching to mode: "full" in outworkos.config.yaml.
Threading
Always thread replies correctly. This requires three fields:
| Field | Value | Purpose |
|---|
thread_id | Gmail thread ID from the original message search | Groups messages in the same conversation |
in_reply_to | Message-ID header from the message being replied to | Links reply to specific parent |
references | Space-separated chain of all Message-ID headers in the thread | Full thread ancestry |
How to get these values:
search_gmail_messages to find the thread
get_gmail_message_content or get_gmail_thread_content to read messages and extract Message-ID headers
- Use the thread ID from the search result, and the
Message-ID from the most recent message as in_reply_to
If Message-ID headers are not available from the MCP tool response, use in_reply_to and references from the last message in the thread (they're usually echoed in the raw headers).
Default Configuration
| Setting | Value |
|---|
| Sender email | Retrieved from user_profiles.email via Supabase MCP |
| Body format | html (required for signature rendering) |
| Signature | Auto-appended by tool (include_signature: true default). Do NOT embed manually. |
Workflow
- Retrieve user profile: Query
user_profiles for email, display_name, scheduling_link, and domain (see Runtime Context above)
- Gather context: Read the relevant thread (if replying) to understand tone and history
- Compose: Write the email following style rules above
- Self-check: Before calling the tool, scan the draft for em dashes, en dashes, AI tells, and filler phrases. Fix any violations.
- Present to user: Show the full email text for approval before creating the draft/send
- Create draft or send: Use the appropriate MCP tool based on user intent
- Confirm: Report the draft ID or sent message ID back to the user
Pre-Send Checklist
Run this mental checklist before every email tool call:
Step 8: Reply Tracking
Database: Use Supabase MCP execute_sql with the project ID from $SUPABASE_PROJECT_ID. All reply tracking reads and writes use this project. Never use other databases for reply tracking.
After confirming the draft or send (Step 7), ask:
Are you expecting a reply to this?
If the user says yes:
-
Store a tracking record in reply_tracking:
INSERT INTO reply_tracking (
user_id, gmail_thread_id, recipient_name, recipient_emails,
subject, summary, sent_at, status, project_slug
) VALUES (
auth.uid(),
'{thread_id}',
'{recipient_name}',
ARRAY['{email1}', '{email2}'],
'{subject}',
'{brief summary of what was asked or requested}',
now(),
'waiting',
'{project_slug or NULL}'
);
-
Create a Todoist task with the waiting-reply label:
-
Store the Todoist task ID back into reply_tracking:
UPDATE reply_tracking SET todoist_task_id = '{task_id}'
WHERE gmail_thread_id = '{thread_id}' AND user_id = auth.uid() AND status = 'waiting';
If the user says no, skip tracking entirely.
When NOT to Ask
Skip the reply tracking question for:
- Internal team emails to the user's own domain (from
user_profiles.domain) unless the user explicitly asks
- Simple confirmations ("Got it", "Thanks", "Sounds good")
- FYI/announcement emails with no ask
AI Suggestion Mode
If the email clearly contains a question or request (e.g., "Can you send me...?", "What do you think about...?", "Let me know if...", "When can we...?", scheduling a meeting link), suggest tracking proactively:
This looks like you're expecting a reply (you asked about X). Want me to track it?
This keeps the flow manual but prevents forgetting. Over time, the patterns from reply_tracking records will inform automation.