rowboat/apps/skills/draft-emails/SKILL.md
tusharmagar e23f4ad6d2 Move skills into apps/skills/, drop override + sync layers
Skills now ship with the app under /apps/skills/ (sibling of /apps/x).
Forge bundles the directory into Resources/skills/; main resolves it via
process.resourcesPath in production and a workspace-relative path in dev,
then registers it in the DI container. The runtime reads SKILL.md files
directly from the bundle — no copy to ~/.rowboat/skills/, no GitHub
tarball sync.

Drop the override layer (FSSkillsRepo, SkillOverride, edit/diff UI,
skill-update notification) since skills are now read-only and only ship
with app updates. Resolver simplifies to a single source.

Add a placeholder substitution layer so skills that need live data
(currently `tracks`, with {{TRACK_BLOCK_SCHEMA}}) keep dynamic content
without depending on TS-module evaluation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 08:35:09 +05:30

8 KiB

name description license compatibility metadata
draft-emails Process incoming emails and create draft responses using calendar and knowledge base for context. Use when the user wants to reply to emails or draft email responses. MIT Designed for Rowboat desktop app
version title author tags
1.1.0 Draft Emails rowboatlabs email, productivity

Email Draft Skill

You are helping the user draft email responses. Use their calendar and knowledge base for context.

CRITICAL: Always Look Up Context First

BEFORE drafting any email, you MUST look up the person/organization in the knowledge base.

PATH REQUIREMENT: Always use `knowledge/` as the path (not empty, not root, not `~/.rowboat`).

  • WRONG: `path: ""` or `path: "."`
  • CORRECT: `path: "knowledge/"`

When the user says "draft an email to Monica" or mentions ANY person, organization, project, or topic:

  1. STOP - Do not draft anything yet
  2. SEARCH - Look them up in the knowledge base (path MUST be `knowledge/`): ``` workspace-grep({ pattern: "Monica", path: "knowledge/" }) ```
  3. READ - Read their note to understand who they are: ``` workspace-readFile("knowledge/People/Monica Smith.md") ```
  4. UNDERSTAND - Extract their role, organization, relationship history, past interactions, open items
  5. THEN DRAFT - Only now draft the email, using this context

DO NOT skip this step. DO NOT provide generic templates. If you don't look up the context first, you will give a useless generic response.

Key Principles

Ask, don't guess:

  • If the user's intent is unclear, ASK them what the email should be about
  • If a person has multiple contexts (e.g., different projects, topics), ASK which one they want to discuss
  • WRONG: "Here are three variants for different contexts - pick one"
  • CORRECT: "I see Akhilesh is involved in Rowboat, banking/ODI, and APR. Which topic would you like to discuss in this email?"

Be decisive, not generic:

  • Once you know the context, draft ONE email - no multiple versions or options
  • Do NOT provide generic templates - every draft should be personalized based on knowledge base context
  • Infer the right tone, content, and approach from the context you gather
  • Do NOT hedge with "here are a few options" or "you could say X or Y" - either ask for clarification OR make a decision and draft ONE email

State Management

All state is stored in `pre-built/email-draft/`:

  • `state.json` - Tracks processing state: ```json { "lastProcessedTimestamp": "2025-01-10T00:00:00Z", "drafted": ["email_id_1", "email_id_2"], "ignored": ["spam_id_1", "spam_id_2"] } ```
  • `drafts/` - Contains draft email files

Initialization

On first run, check if state exists. If not, create it:

  1. Check if `pre-built/email-draft/state.json` exists
  2. If not, create `pre-built/email-draft/` and `pre-built/email-draft/drafts/`
  3. Initialize `state.json` with empty arrays and a timestamp of "1970-01-01T00:00:00Z"

Processing Flow

Step 1: Load State

Read `pre-built/email-draft/state.json` to get:

  • `lastProcessedTimestamp` - Only process emails newer than this
  • `drafted` - List of email IDs already drafted (skip these)
  • `ignored` - List of email IDs marked as ignored (skip these)

Step 2: Scan for New Emails

List emails in `gmail_sync/` folder.

For each email file:

  1. Extract the email ID from filename (e.g., `19048cf9c0317981.md` -> `19048cf9c0317981`)
  2. Skip if ID is in `drafted` or `ignored` lists
  3. Read the email content

Step 3: Parse Email

Each email file contains: ```markdown

Subject Line

Thread ID: Message Count:


From: Name email@example.com

Date:

\`\`\`

Extract:

  • Thread ID (this is the email ID)
  • From (sender name and email)
  • Date
  • Subject (from the # heading)
  • Body content
  • Message count (to understand if it's a thread)

Step 4: Classify Email

Determine the email type and action:

IGNORE these (add to `ignored` list):

  • Newsletters (unsubscribe links, "View in browser", bulk sender indicators)
  • Marketing emails (promotional language, no-reply senders)
  • Automated notifications (GitHub, Jira, Slack, shipping updates)
  • Spam or cold outreach that's clearly irrelevant
  • Emails where you (the user) are the sender and it's outbound with no reply

DRAFT response for:

  • Meeting requests or scheduling emails
  • Personal emails from known contacts
  • Business inquiries that seem legitimate
  • Follow-ups on existing conversations
  • Emails requesting information or action

Step 5: Gather Context

Before drafting, gather relevant context. Always check the knowledge base first for any person, organization, project, or topic mentioned in the email.

Knowledge Base Context (REQUIRED):

First, search for the sender and any mentioned entities (path MUST be `knowledge/`): ```

Search for the sender by name or email

workspace-grep({ pattern: "sender_name_or_email", path: "knowledge/" })

List all people to find potential matches

workspace-readdir("knowledge/People") ```

Then read the relevant notes: ```

Read the sender's note

workspace-readFile("knowledge/People/Sender Name.md")

Read their organization's note

workspace-readFile("knowledge/Organizations/Company Name.md") ```

Extract from these notes:

  • Their role, title, and organization
  • History of past interactions and meetings
  • Commitments made (by them or to them)
  • Open items and pending actions
  • Relationship context and rapport

Use this context to provide informed, personalized responses that demonstrate you remember past interactions.

Calendar Context (for scheduling emails):

  • Read calendar events from `calendar_sync/` folder
  • Look for events in the relevant time period
  • Check for conflicts, availability

Step 6: Create Draft

For emails that need a response, create a draft file in `pre-built/email-draft/drafts/`:

Filename: `{email_id}_draft.md`

Content format: ```markdown

Draft Response

Original Email ID: {email_id} Original Subject: {subject} From: {sender} Date Processed: {current_date}


Context Used

  • Calendar: {relevant calendar info or "N/A"}
  • Memory: {relevant notes or "N/A"}

Draft Response

Subject: Re: {original_subject}

{draft email body}


Notes

{any notes about why this response was crafted this way} ```

Drafting Guidelines:

  • Draft ONE email - do not offer multiple versions or options unless explicitly asked
  • Be concise and professional
  • For scheduling: propose specific times based on calendar availability
  • For inquiries: answer directly or indicate what info is needed
  • Reference any relevant context from memory naturally - show you remember past interactions
  • Match the tone of the incoming email
  • If it's a thread with multiple messages, read the full context
  • Do NOT use generic templates or placeholder language - personalize based on knowledge base
  • If you're unsure about the user's intent, ask a clarifying question first

Step 7: Update State

After processing each email:

  1. Add the email ID to either `drafted` or `ignored` list
  2. Update `lastProcessedTimestamp` to the current time
  3. Write updated state to `pre-built/email-draft/state.json`

Output

After processing all new emails, provide a summary:

```

Processing Summary

Emails Scanned: X Drafts Created: Y Ignored: Z

Drafts Created:

  • {email_id}: {subject} - {brief reason}

Ignored:

  • {email_id}: {subject} - {reason for ignoring} ```

Error Handling

  • If an email file is malformed, log it and continue
  • If calendar/notes folders don't exist, proceed without that context
  • Always save state after each email to avoid reprocessing on failure

Important Notes

  • Never actually send emails - only create drafts
  • The user will review and send drafts manually
  • Be conservative with ignore - when in doubt, create a draft
  • For ambiguous emails, create a draft with a note explaining the ambiguity