templates/mail/.agents/skills/email-drafts/SKILL.md
# Email Drafts Create, edit, and manage email drafts. Each draft is stored as an application state entry keyed `compose-{id}`. The UI watches for changes via SSE and updates the compose panel in real time. ## Storage Drafts are stored in the `application_state` SQL table via `writeAppState("compose-{id}", draft)` from `@agent-native/core/application-state`. Each entry is one draft. Multiple drafts can exist simultaneously — they appear as tabs in the compose panel. ## Schema ```json { "id
npx skillsauth add BuilderIO/agent-native templates/mail/.agents/skills/email-draftsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create, edit, and manage email drafts. Each draft is stored as an application state entry keyed compose-{id}. The UI watches for changes via SSE and updates the compose panel in real time.
Drafts are stored in the application_state SQL table via writeAppState("compose-{id}", draft) from @agent-native/core/application-state. Each entry is one draft. Multiple drafts can exist simultaneously — they appear as tabs in the compose panel.
{
"id": "abc123",
"to": "[email protected]",
"cc": "",
"bcc": "",
"subject": "Meeting follow-up",
"body": "Hi team,\n\nThanks for the great discussion today...",
"mode": "compose",
"replyToId": "",
"replyToThreadId": ""
}
| Field | Type | Required | Description |
| ----------------- | ------ | -------- | ----------------------------------------------- |
| id | string | yes | Unique draft ID (must match key suffix) |
| to | string | yes | Comma-separated recipient email addresses |
| cc | string | no | Comma-separated CC addresses |
| bcc | string | no | Comma-separated BCC addresses |
| subject | string | yes | Email subject line |
| body | string | yes | Email body in markdown (see formatting below) |
| mode | string | yes | One of: "compose", "reply", "forward" |
| replyToId | string | no | Message ID being replied to (for reply/forward) |
| replyToThreadId | string | no | Thread ID for grouping (for reply/forward) |
The body field uses markdown. The compose editor (TipTap) renders it as rich text, and the send flow converts markdown to HTML before sending via Gmail. Use standard markdown syntax:
[click here](https://example.com) — renders as a clickable hyperlink in the sent email**bold text***italic text*- item (unordered) or 1. item (ordered)# Heading (h1–h3)`inline code` or fenced code blocks> quoted texthttps://example.com auto-linksDo NOT use raw HTML tags — use markdown only.
writeAppState("compose-{id}", draft) — the store emits an SSE eventcompose-drafts React Query cacheThe compose panel opens automatically when any compose draft exists. When the last draft is deleted, the panel closes.
Use the manage-draft script or write directly:
pnpm action manage-draft --action=create [email protected] --subject="Quick question" --body="Hi Jane,\n\nJust wanted to follow up on..."
Or from code:
import { writeAppState } from "@agent-native/core/application-state";
await writeAppState("compose-draft1", {
id: "draft1",
to: "[email protected]",
subject: "Quick question",
body: "Hi Jane,\n\nJust wanted to follow up on...",
mode: "compose",
});
Read the current draft, modify it, write it back:
import { readAppState, writeAppState } from "@agent-native/core/application-state";
const draft = await readAppState("compose-draft1");
draft.body = "Hi Jane,\n\nI refined the draft as requested...";
await writeAppState("compose-draft1", draft);
pnpm action view-composer
Or from code:
import { listAppState } from "@agent-native/core/application-state";
const drafts = await listAppState("compose-");
import { deleteAppState } from "@agent-native/core/application-state";
await deleteAppState("compose-draft1");
id field in the JSON MUST match the {id} in the key name (compose-{id})\n)compose-abc123). Always update THAT entry — do NOT create a new one with a different ID. Read, modify, and write back to the same key.tools
Public booking flow — the state machine, animations, and URL/app-state sync.
tools
Trigger-based automations — reminders, follow-ups, webhooks — across the booking lifecycle.
tools
Team event types, round-robin assignment, collective bookings, host weights, and no-show calibration.
development
The pure `computeAvailableSlots` function — inputs, outputs, invariants, and debugging guide.