listener-creator について
listener-creator は、メールイベントを監視して処理を実行する TypeScript リスナー作成スキルです。AI による分類やスケジュール実行を含むメールワークフローの設定を支援します。
主な機能
- 01TypeScript メールリスナーの作成
- 02複数のメールイベントへの対応
- 03メール内容のフィルタリングと分類
- 04通知、アーカイブ、スター、ラベル付け
- 05メール処理のスケジュール設定
活用シーン
- 01緊急メールの到着通知
- 02ニュースレターの自動アーカイブ
- 03荷物関連メールの追跡
- 04定時メールサマリーの送信
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ anthropics/ claude-agent-sdk-demos --skill listener-creatorインストール後、Claude Code で/listener-creatorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
templates/ai-classifier.tsauto-archive.tspackage-tracker.tsurgent-watcher.ts詳細
リスナー作成
メールイベントを監視し、条件を満たしたときにカスタムロジックを実行する TypeScript リスナーファイルを作成します。
このスキルを使う場面
ユーザーが次のことを希望している場合に、このスキルを使います。
- 特定のメールについて通知を受け取る(「上司から緊急メールが届いたら通知して」)
- 特定のメールを自動処理する(「ニュースレターを自動アーカイブして」)
- パターンを監視する(「荷物の追跡メールを監視して」)
- スケジュールに沿ったアクションを設定する(「毎日午前9時にメールの要約を送って」)
- カスタムメールワークフローを作成する
リスナーの仕組み
リスナーは agent/custom_scripts/listeners/ にある TypeScript ファイルで、次の処理を行います。
- イベントタイプとメタデータを定義する
configオブジェクトをエクスポートする - イベントをフィルタリングして処理する
handler関数をエクスポートする ListenerContextのメソッドを使ってアクション(通知、アーカイブ、スター付けなど)を実行する
システムは有効なリスナーを自動的に読み込み、一致するイベントが発生したときに実行します。
リスナーの作成
1. ユーザーの意図を理解する
ユーザーのリクエストを解析し、次の内容を特定します。
- イベントタイプ:このリスナーを起動するものは何ですか?(email_received、email_sent、email_starred、email_archived、email_labeled、scheduled_time)
- フィルター条件:どのメール/イベントを照合しますか?(送信者、件名のキーワード、時刻ベース)
- アクション:何を実行しますか?(通知、アーカイブ、スター付け、既読にする、ラベルを追加する)
- 優先度:どの程度緊急ですか?(high/normal/low)
2. イベントタイプを選択する
// Available event types:
- "email_received" // Most common - new email arrives
- "email_sent" // User sends an email
- "email_starred" // Email is starred
- "email_archived" // Email is archived
- "email_labeled" // Label added to email
- "scheduled_time" // Time-based (cron) - requires scheduler setup
3. リスナーファイルを作成する
agent/custom_scripts/listeners/ に次の構造でファイルを作成します。
import type { ListenerConfig, Email, ListenerContext } from "../types";
export const config: ListenerConfig = {
id: "unique_listener_id", // kebab-case, descriptive
name: "Human Readable Name", // For UI display
description: "What this does", // Optional but helpful
enabled: true, // Start enabled
event: "email_received" // Event type
};
export async function handler(email: Email, context: ListenerContext): Promise<void> {
// 1. Basic filter (identity/sender only)
if (!email.from.includes("[email protected]")) return;
// 2. Use AI for intelligent classification (PREFERRED over keyword matching)
const analysis = await context.callAgent<{ isUrgent: boolean; reason: string }>({
prompt: `Is this email urgent?\nSubject: ${email.subject}\nBody: ${email.body.substring(0, 500)}`,
schema: {
type: "object",
properties: {
isUrgent: { type: "boolean" },
reason: { type: "string" }
},
required: ["isUrgent", "reason"]
},
model: "haiku"
});
if (!analysis.isUrgent) return;
// 3. Perform actions via context methods
await context.notify(`Urgent email: ${email.subject}\n${analysis.reason}`, {
priority: "high"
});
await context.starEmail(email.messageId);
}
4. ファイル名の規則
リスナーの目的に合わせて、ケバブケースのファイル名を使います。
boss-urgent-watcher.tsauto-archive-newsletters.tspackage-tracking.tsdaily-summary.ts
5. 使用可能なコンテキストメソッド
ListenerContext では、次のメソッドを使用できます。
// Notifications
await context.notify(message, { priority: "high" | "normal" | "low" });
// Email actions
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");
// AI-powered analysis
const result = await context.callAgent<ResultType>({
prompt: "Your prompt with email content",
schema: {
type: "object",
properties: { field: { type: "string" } },
required: ["field"]
},
model: "haiku" // or "sonnet" or "opus"
});
推奨される方法:AI を活用した分類
固定されたキーワードリストを使うのではなく、賢く判断できるように、デフォルトでは context.callAgent() を使います。これにより、精度と柔軟性が向上します。
// PREFERRED: AI-based urgency detection
const analysis = await context.callAgent<{ isUrgent: boolean; reason: string }>({
prompt: `Analyze if this email is urgent:
Subject: ${email.subject}
Body: ${email.body.substring(0, 500)}
Is this email urgent or time-sensitive? Consider context, not just keywords.`,
schema: {
type: "object",
properties: {
isUrgent: { type: "boolean" },
reason: { type: "string" }
},
required: ["isUrgent", "reason"]
},
model: "haiku" // Fast and cost-effective
});
if (analysis.isUrgent) {
await context.notify(`Urgent: ${email.subject}\n${analysis.reason}`);
}
// AVOID: Hard-coded keyword lists (brittle and prone to false positives)
// const isUrgent = subject.includes("urgent") || subject.includes("asap");
例とテンプレート
よく使われるパターンについては、テンプレートファイルを参照してください。
- ai-classifier.ts:⭐ AI を活用したメール分類(推奨)
- urgent-watcher.ts:AI ベースの緊急メール検出
- auto-archive.ts:ニュースレターを自動的にアーカイブ
- package-tracker.ts:ステータス抽出を伴う荷物追跡
ベストプラクティス
- AI による分類を優先する:賢く判断するには、固定されたキーワードリストではなく
context.callAgent()を使います - 早い段階でフィルタリングする:メールが基本条件(送信者など)に一致しない場合は、早期に戻ります
- わかりやすい ID を使う:説明的で一意なリスナー ID を使います
- エラーを処理する:適切な場合は、コンテキストメソッドの呼び出しを try-catch で囲みます
- パフォーマンスに配慮する:AI による分類には、高速な "haiku" モデルを使います(通常は1秒未満)
- 通知は慎重に行う:本当に重要な場合にのみ通知します
- 固定リストを避ける:キーワード照合ではなく、緊急度、重要度、カテゴリを AI に判断させます
型のインポート
型は必ず正しい場所からインポートしてください。
import type { ListenerConfig, Email, ListenerContext } from "../types";
// For scheduled listeners:
import type { ListenerConfig, ListenerContext } from "../types";
// For labeled event:
import type { ListenerConfig, Email, ListenerContext } from "../types";
よく使われるパターン
AI を活用する方法(推奨)
基本的なフィルター(送信者/種類)→ AI エージェントを呼び出して分類 → AI の結果に応じて対応 → 重要な場合は通知
次のような利点があるため、ほとんどのリスナーでこの方法を推奨します。
- 脆弱なキーワード照合を避けられる
- 微妙な表現や文脈に適応できる
- 緊急度やカテゴリをより適切に判断できる
- 誤検出を減らせる
シンプルな通知(使用は控えめに)
基本的なフィルター(送信者のみ)→ 通知 → 必要に応じてスター付け/ラベル付け
次の場合にのみ使用します:トリガーが送信者の識別だけに基づく場合(例:「X からのメールをすべて通知して」)
自動アーカイブ
基本的なフィルター → アーカイブ → 既読にする → 必要に応じて通知
スケジュール実行
指定した時刻に実行 → メールを検索 → 分析 → 要約を送信
ファイルの作成
ユーザーからリスナーの作成を依頼された場合:
-
意図が不明確な場合は、確認の質問をします:
- 送信者は誰ですか?キーワードは何ですか?
- どのようなアクションを実行しますか?
- 緊急度はどの程度ですか?
-
適切なイベントタイプを選択します(通常は
email_received) -
agent/custom_scripts/listeners/に TypeScript ファイルを作成します -
Write ツールを使用してファイルを作成します。ファイルには次の内容を含めます:
- 適切なインポート
- 説明的な設定
- 早期フィルタリングを行うハンドラー
- 適切なコンテキストメソッドの呼び出し
-
UI で簡単に解析・リンクできるよう、
[listener:filename.ts]表記(例:[listener:boss-urgent-watcher.ts])を使って、リスナーの参照を Markdown 形式で返します -
作成したリスナーがユーザーの意図に合っていることを ユーザーに確認します
出力形式の例
作成したリスナーをユーザーに提示する際は、次の形式を使用します:
Created listener: [listener:boss-urgent-watcher.ts]
This listener will:
- Monitor emails from [email protected]
- Use AI to detect urgent emails (not just keywords)
- Send high-priority notifications for truly urgent emails
- Star emails that require immediate action
AI と単純なフィルタリングの使い分け
次の場合は AI(context.callAgent())を使用します:
- 緊急度、重要度、または感情を検出する
- メールの内容や意図を分類する
- メール本文から構造化データを抽出する
- コンテキストに基づいて、微妙な判断を行う
- メール内容の「理解」を伴うロジックを扱う
次の場合は単純なフィルタリングを使用します:
- 送信者または宛先が完全一致するかを確認する
- メールフィールドの基本的なパターンマッチングを行う(例:「特定のドメインからのメール」)
- ID に基づくトリガーを設定する(例:「X さんからのすべてのメール」)
フィルターが ID のみに基づく場合を除き、AI をデフォルトで使用します。
スケジュールされたリスナー
時間ベースのアクション(毎日の要約、週次レポート)には、次を使用します:
export const config: ListenerConfig = {
id: "daily_summary",
name: "Daily Email Summary",
enabled: true,
event: "scheduled_time"
// Note: Cron schedule configured separately in scheduler
};
export async function handler(
data: { timestamp: Date },
context: ListenerContext
): Promise<void> {
// Your scheduled logic here
await context.notify("Good morning! Your daily summary...");
}
注:スケジュールされたリスナーには、リスナーファイルの外部で cron スケジューラーを設定する必要があります。
参考資料
完全な仕様については、プロジェクトのルートにある LISTENERS_SPEC.md を参照してください。次の内容を網羅しています:
- すべてのイベントタイプ
- 型定義の全容
- ListenersManager の実装
- 応用例
- エラー処理のパターン