npx skills add ...
npx skills add anthropics/claude-agent-sdk-demos --skill action-creator
npx skills add anthropics/claude-agent-sdk-demos --skill action-creator
Creates user-specific one-click action templates that execute email operations when clicked in the chat interface. Use when user wants reusable actions for their specific workflows (send payment reminder to ACME Corp, forward bugs to engineering, archive old newsletters from specific sources).
Creates TypeScript action template files that define reusable, user-specific operations users can execute with one click in the chat interface.
Use this skill when the user wants to:
Key difference from listeners: Actions are user-triggered (clicked in chat), while listeners are event-triggered (automatic).
Actions are TypeScript files in agent/custom_scripts/actions/ that:
config object defining the template metadata and parameter schemahandler function that executes the operation with given parametersActionContext methods to perform operations (email API, send emails, call AI, etc.)The agent creates action instances during conversation by providing specific parameters to these templates, which appear as clickable buttons in the chat.
Parse the user's request to identify:
Create a file in agent/custom_scripts/actions/ with this structure:
Use kebab-case that reflects the user-specific operation:
send-payment-reminder-to-acme.ts (not send-email.ts)forward-bugs-to-engineering.ts (not forward-email.ts)archive-newsletters-from-techcrunch.ts (not archive-emails.ts)summarize-weekly-updates-from-ceo.ts (not summarize-emails.ts)Important: Templates should be specific to the user's actual workflows, vendors, teams, and processes.
The ActionContext provides these capabilities:
Always return an ActionResult object:
Reference the template files for common patterns:
context.callAgent() for intelligent processingcontext.log() for debugging and audit trailDefine parameters using JSON Schema:
When the user requests an action template:
Clarify user-specific context:
Write the TypeScript file in agent/custom_scripts/actions/
Use Write tool to create the file with:
Test parameters: Ensure all required parameters are defined
Confirm with user that the action matches their workflow
User-specific → Compose email with template → Send → Return result
Search emails → Filter → Apply operation to each → Return count
Get email → Call AI to analyze → Use AI result → Take action → Return summary
Get email → AI analysis → Compose enhanced forward → Send → Label original
Always import types from the correct location:
After you create an action template:
Example flow:
Full specification: See project root ACTIONS_SPEC.md for complete details on:
// Email API operations
const emails = await context.emailAPI.getInbox({ limit: 30, includeRead: false });
const results = await context.emailAPI.searchEmails({ from: "sender@example.com" });
const results = await context.emailAPI.searchWithGmailQuery("from:sender after:2024/01/01");
const emails = await context.emailAPI.getEmailsByIds(["id1", "id2"]);
const email = await context.emailAPI.getEmailById("email-id");
// Direct email operations
await context.archiveEmail(emailId);
await context.starEmail(emailId);
await context.unstarEmail(emailId);
await context.markAsRead(emailId);
await context.markAsUnread(emailId);
await context.addLabel(emailId, "label-name");
await context.removeLabel(emailId, "label-name");
// Send emails
const result = await context.sendEmail({
to: "recipient@example.com",
subject: "Email subject",
body: "Email body content",
cc: "cc@example.com", // Optional
bcc: "bcc@example.com", // Optional
replyTo: "reply@example.com" // Optional
});
// AI-powered processing
const analysis = await context.callAgent<ResultType>({
prompt: "Analyze this email and extract key info...",
systemPrompt: "You are an expert at...", // Optional
tools: ["Read", "WebSearch"], // Optional
maxTokens: 2000 // Optional
});
// Session messaging (inject into chat)
context.addUserMessage("User said this");
context.addAssistantMessage("Assistant responds");
context.addSystemMessage("System notification");
// Notifications
context.notify("Operation completed", {
priority: "high" | "normal" | "low",
type: "info" | "success" | "warning" | "error"
});
// External API access
const response = await context.fetch("https://api.example.com/data");
const data = await response.json();
// Logging (visible in server logs)
context.log("Info message", "info");
context.log("Warning message", "warn");
context.log("Error message", "error");return {
success: true, // Required: boolean
message: "Human-readable result", // Required: string
data: { key: "value" }, // Optional: structured data
suggestedActions: [], // Optional: follow-up actions
refreshInbox: true // Optional: refresh inbox
};parameterSchema: {
type: "object",
properties: {
// String parameter
emailId: {
type: "string",
description: "Email ID to process"
},
// Number parameter with default
daysOld: {
type: "number",
description: "Number of days old",
default: 30
},
// Enum parameter (dropdown)
priority: {
type: "string",
description: "Priority level",
enum: ["P0 - Critical", "P1 - High", "P2 - Medium", "P3 - Low"]
},
// Boolean parameter
sendNotification: {
type: "boolean",
description: "Send notification when complete"
}
},
required: ["emailId", "priority"] // List required params
}const body = `Hi ${recipientName},
Your invoice ${invoiceNumber} for ${amount} is ${daysPastDue} days past due...`;
await context.sendEmail({
to: "accounts.payable@acmecorp.com",
subject: `Payment Reminder: Invoice ${invoiceNumber}`,
body
});const emails = await context.emailAPI.searchWithGmailQuery(query);
for (const email of emails) {
await context.archiveEmail(email.messageId);
}
return { success: true, message: `Archived ${emails.length} emails` };const email = await context.emailAPI.getEmailById(emailId);
const analysis = await context.callAgent({
prompt: `Analyze this bug report: ${email.body}...`,
maxTokens: 1000
});
await context.sendEmail({ to: "engineering@company.com", ... });const email = await context.emailAPI.getEmailById(emailId);
const analysis = await context.callAgent({ /* analyze */ });
await context.sendEmail({
to: "team@company.com",
subject: `[${priority}] ${email.subject}`,
body: `AI Analysis:\n${analysis}\n\nOriginal:\n${email.body}`
});
await context.addLabel(emailId, "FORWARDED");import type { ActionTemplate, ActionContext, ActionResult } from "../types";
// ActionTemplate: Template metadata and parameter schema
// ActionContext: Runtime context with all capabilities
// ActionResult: Return type for handler functionUser: "I need to follow up on the ACME invoice"
Agent: [searches emails, finds Invoice #2024-001 is 15 days overdue]
Agent: Creates action instance with parameters:
{
templateId: "send_payment_reminder_acme",
params: { invoiceNumber: "INV-2024-001", amount: "$5,000", daysPastDue: 15 }
}
User: [sees button "Send payment reminder to ACME Corp for Invoice #2024-001"]
User: [clicks button]
Action: Executes, sends email, returns "Payment reminder sent to ACME Corp"