mcpField
L
listener-creator

listener-creator

github.com/anthropics生産性2.8k165 回インストール33 週間前に更新
リポジトリ

listener-creator について

listener-creator は、メールイベントを監視して処理を実行する TypeScript リスナー作成スキルです。AI による分類やスケジュール実行を含むメールワークフローの設定を支援します。

主な機能

  1. 01TypeScript メールリスナーの作成
  2. 02複数のメールイベントへの対応
  3. 03メール内容のフィルタリングと分類
  4. 04通知、アーカイブ、スター、ラベル付け
  5. 05メール処理のスケジュール設定

活用シーン

  1. 01緊急メールの到着通知
  2. 02ニュースレターの自動アーカイブ
  3. 03荷物関連メールの追跡
  4. 04定時メールサマリーの送信

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/anthropics/claude-agent-sdk-demos --skill listener-creator

インストール後、Claude Code で/listener-creatorを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

templates/
ai-classifier.ts
auto-archive.ts
package-tracker.ts
urgent-watcher.ts

詳細

リスナー作成

メールイベントを監視し、条件を満たしたときにカスタムロジックを実行する TypeScript リスナーファイルを作成します。

このスキルを使う場面

ユーザーが次のことを希望している場合に、このスキルを使います。

  • 特定のメールについて通知を受け取る(「上司から緊急メールが届いたら通知して」)
  • 特定のメールを自動処理する(「ニュースレターを自動アーカイブして」)
  • パターンを監視する(「荷物の追跡メールを監視して」)
  • スケジュールに沿ったアクションを設定する(「毎日午前9時にメールの要約を送って」)
  • カスタムメールワークフローを作成する

リスナーの仕組み

リスナーは agent/custom_scripts/listeners/ にある TypeScript ファイルで、次の処理を行います。

  1. イベントタイプとメタデータを定義する config オブジェクトをエクスポートする
  2. イベントをフィルタリングして処理する handler 関数をエクスポートする
  3. 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.ts
  • auto-archive-newsletters.ts
  • package-tracking.ts
  • daily-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");

例とテンプレート

よく使われるパターンについては、テンプレートファイルを参照してください。

ベストプラクティス

  1. AI による分類を優先する:賢く判断するには、固定されたキーワードリストではなく context.callAgent() を使います
  2. 早い段階でフィルタリングする:メールが基本条件(送信者など)に一致しない場合は、早期に戻ります
  3. わかりやすい ID を使う:説明的で一意なリスナー ID を使います
  4. エラーを処理する:適切な場合は、コンテキストメソッドの呼び出しを try-catch で囲みます
  5. パフォーマンスに配慮する:AI による分類には、高速な "haiku" モデルを使います(通常は1秒未満)
  6. 通知は慎重に行う:本当に重要な場合にのみ通知します
  7. 固定リストを避ける:キーワード照合ではなく、緊急度、重要度、カテゴリを 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 からのメールをすべて通知して」)

自動アーカイブ

基本的なフィルター → アーカイブ → 既読にする → 必要に応じて通知

スケジュール実行

指定した時刻に実行 → メールを検索 → 分析 → 要約を送信

ファイルの作成

ユーザーからリスナーの作成を依頼された場合:

  1. 意図が不明確な場合は、確認の質問をします:

    • 送信者は誰ですか?キーワードは何ですか?
    • どのようなアクションを実行しますか?
    • 緊急度はどの程度ですか?
  2. 適切なイベントタイプを選択します(通常は email_received)

  3. agent/custom_scripts/listeners/ に TypeScript ファイルを作成します

  4. Write ツールを使用してファイルを作成します。ファイルには次の内容を含めます:

    • 適切なインポート
    • 説明的な設定
    • 早期フィルタリングを行うハンドラー
    • 適切なコンテキストメソッドの呼び出し
  5. UI で簡単に解析・リンクできるよう、[listener:filename.ts] 表記(例:[listener:boss-urgent-watcher.ts])を使って、リスナーの参照を Markdown 形式で返します

  6. 作成したリスナーがユーザーの意図に合っていることを ユーザーに確認します

出力形式の例

作成したリスナーをユーザーに提示する際は、次の形式を使用します:

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 の実装
  • 応用例
  • エラー処理のパターン

コメント