mcpField
E
extract-my-action-items

extract-my-action-items

github.com/casper-studios生産性15291 回インストール8 週間前に更新
リポジトリ

extract-my-action-items について

Fireflies の会議トランスクリプトから、全参加者または指定した人のアクション項目を抽出するスキルです。サブエージェントで内容を並列処理し、ノートをまとめて Linear の提案やアクション項目ファイルを作成します。

主な機能

  1. 01全参加者または個人の項目を抽出
  2. 02日付、キーワード、IDでトランスクリプトを検索
  3. 03サブエージェントで分割処理
  4. 04引用付きのカテゴリ別ノートを作成
  5. 05Linear のチケット提案を準備
  6. 06チェックリスト作成と Slack DM 送信

活用シーン

  1. 01会議記録から担当者と約束事項を特定
  2. 02アクション項目の背景や決定内容を記録
  3. 03レビュー用の Linear チケット案を準備
  4. 04参加者別の項目をまとめて配布

MCP 対応

サブエージェントが Fireflies MCP ツールを使い、トランスクリプト、要約、本文を検索・取得するよう指示します。Linear MCP ツールによるチケット検索や更新も指定されています。

インストール

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

$npx skills add https://github.com/casper-studios/casper-marketplace --skill extract-my-action-items

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

同梱ファイル

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

references/
config.json
ticket-template.md
scripts/
fetch-slack-users.mjs
slack-post.mjs

詳細

アクション項目を抽出する

並列サブエージェントを使用して、Fireflies の文字起こしからアクション項目を抽出します。自動生成された要約で見落とされる項目も検出できます。

2 つのモード:

  • 全参加者(デフォルト): 対象者の指定なし — すべての参加者のアクション項目を抽出します
  • 1 人の人物: 対象者の指定あり — その人物のアクション項目のみを抽出します

フェーズ 1:モードを判定する

ユーザーの呼び出し内容を解析します:

  • 対象者が指定されている場合 → 1 人の人物モード
  • それ以外の場合 → 全参加者モード

呼び出し内容から検索条件(日付、キーワード、または文字起こし ID)を抽出します。

フェーズ 2:取得と前処理(サブエージェント)

文字起こし API は JSON 配列(またはそれを含む MCP ラッパー)を返します。チャンク分割の前に、プレーンテキストに変換します。

ユーザーのローカルフック設定を確認し、フックでブロックされるコマンドは実行しないでください。

MCP ベースの抽出
mkdir -p .claude/scratchpad
node -e "
  const fs = require('fs');
  let data = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
  // Handle MCP wrapper: if top-level array has a .text field containing the real transcript, parse that
  if (data.length === 1 && typeof data[0]?.text === 'string') {
    // Extract speaker lines from the text content
    const lines = data[0].text.split('\n').filter(l => l.match(/^[A-Za-z].*?:/));
    fs.writeFileSync('.claude/scratchpad/transcript.txt', lines.join('\n'));
    const speakers = [...new Set(lines.map(l => l.split(':')[0].trim()))].sort();
    console.log('Speakers:', JSON.stringify(speakers));
    console.log('Total lines:', lines.length);
  } else {
    // Standard array of {speaker_name, text} objects
    const lines = data.map(e => (e.speaker_name || 'Unknown') + ': ' + (e.text || ''));
    fs.writeFileSync('.claude/scratchpad/transcript.txt', lines.join('\n'));
    const speakers = [...new Set(data.map(e => e.speaker_name).filter(Boolean))].sort();
    console.log('Speakers:', JSON.stringify(speakers));
    console.log('Total lines:', lines.length);
  }
" [TRANSCRIPT_JSON_FILE]

文字起こしの JSON が MCP クライアントによってツール結果ファイルに保存されている場合は、そのファイルパスを引数として渡します。

API ベースの抽出

重要:オーケストレーターは Fireflies MCP ツールを直接呼び出してはいけません。Fireflies とのやり取りはすべて、このサブエージェント内で行います。

次のプロンプトで general-purpose サブエージェントを 1 つ起動します:

Search Fireflies for a transcript matching: [SEARCH_CRITERIA]

1. Call `mcp__fireflies__fireflies_get_transcripts` to find the transcript (by date, keyword, or ID).
2. Call `mcp__fireflies__fireflies_get_summary` and `mcp__fireflies__fireflies_get_transcript` in parallel for the matched transcript.
3. The transcript API returns a JSON array. Extract to plain text:
   - With jq: jq -r '.[].text' < raw_transcript.json > .claude/scratchpad/transcript.txt
   - Fallback: python3 -c "import json,sys; print('\n'.join(e['text'] for e in json.load(sys.stdin)))" < raw_transcript.json > .claude/scratchpad/transcript.txt
4. Count lines: wc -l < .claude/scratchpad/transcript.txt
5. Extract the distinct speaker list from the transcript JSON:
   python3 -c "import json,sys; data=json.load(sys.stdin); print('\n'.join(sorted(set(e.get('speaker_name','') for e in data if e.get('speaker_name')))))" < raw_transcript.json

Return EXACTLY this (no other text):
- meeting_title: <title>
- meeting_date: <date>
- transcript_id: <id>
- transcript_path: .claude/scratchpad/transcript.txt
- line_count: <number>
- speakers: <comma-separated list>
- summary: <the Fireflies summary text>

サブエージェントが完了するまで待ちます。返された値を解析します。これらが残りのフェーズで使用する入力となります。

フェーズ 3:並列サブエージェントによる抽出

チャンクサイズ: チャンクあたり ceil(total_lines / 5) 行、最小 200 行とします。200 行未満のチャンクがないように、チャンク数を調整します。

チャンクごとに general-purpose サブエージェントを 1 つ起動します。

1 人の人物向けプロンプト
Read lines [START] to [END] of [FILE_PATH].

Find ALL action items for [TARGET_PERSON]. Return each as:
- **Item**: what they committed to
- **Quote**: exact words from transcript
- **Context**: who else involved, any deadline
- **Discussion depth**: If this item emerged from extended back-and-forth (design decisions, technical debates, multi-speaker deliberation), include: what was proposed, what alternatives were considered, what was decided and WHY, specific technical details (field names, schema choices, API behaviors), open questions or deferred items, and connections to other people's work

Beyond obvious commitments ("I'll do X"), catch these non-obvious patterns:
- Self-notes: "I'll make a note to...", "let me jot down..."
- Admissions implying catch-up: "I dropped the ball on X", "I still haven't read X"
- Conditional offers that became commitments: "If we have time, I'm happy to..."
- Volunteering: "I guess I'll volunteer to..."
- Exploration tasks: "Let me spend a few hours with it"
- Questions/topics for external parties: "I need to ask [person/firm] about X", "thing to discuss with [party]"
全参加者向けプロンプト
Read lines [START] to [END] of [FILE_PATH].

The meeting attendees are: [SPEAKER_LIST]

Find ALL action items for EVERY attendee. Group by person. For each item return:
- **Person**: who owns the action item
- **Item**: what they committed to
- **Quote**: exact words from transcript
- **Context**: who else involved, any deadline
- **Discussion depth**: If this item emerged from extended back-and-forth (design decisions, technical debates, multi-speaker deliberation), include: what was proposed, what alternatives were considered, what was decided and WHY, specific technical details (field names, schema choices, API behaviors), open questions or deferred items, and connections to other people's work

Beyond obvious commitments ("I'll do X"), catch these non-obvious patterns:
- Self-notes: "I'll make a note to...", "let me jot down..."
- Admissions implying catch-up: "I dropped the ball on X", "I still haven't read X"
- Conditional offers that became commitments: "If we have time, I'm happy to..."
- Volunteering: "I guess I'll volunteer to..."
- Exploration tasks: "Let me spend a few hours with it"
- Questions/topics for external parties: "I need to ask [person/firm] about X", "thing to discuss with [party]"
- Delegations: "[Person], can you handle X?", "I'll leave that to [person]"

フェーズ 4:ノートを統合する

サブエージェントの結果を統合して重複を除き、詳細な統合ノートファイルに分類します。これは主要な作業ドキュメントです。すべての詳細はここに記録します。Linear の提案と最終的なアクション項目チェックリストは、このファイルをもとに作成します。

.claude/scratchpad/synthesized-notes-YYYY-MM-DD.md に書き込みます。項目があるカテゴリのみを含めてください。

統合の詳細度

サブエージェントが返した Discussion depth を完全な形で保持します。議論の詳細がある項目を、決して一行にまとめないでください。

  • チェックボックスのタイトルは成果物とします。本文には、実行に必要な背景をすべて記載します。
  • サブエージェントが項目について複数段落の背景を返した場合は、それを残します。整理するには 太字の小見出し(例:根本原因:、合意した対応方針:、未解決事項:)を使用します。
  • 別々の決定を 1 つの箇条書きにまとめないでください。それぞれを列挙します。
  • 相互に依存する項目には相互参照を追加します(例:「Emerson の会計期間テーブル作業の依存項目」)。
  • 簡単な項目(認証情報の共有、簡単な調査など)は一行のままにします。
  • 各項目には文字起こしからの正確な引用を含めます。
カテゴリ
  1. 優先度高/技術 — コード変更、バグ修正、PR レビュー、調査
  2. ペア作業/コラボレーション — 予定済みの同期、共同作業セッション
  3. コンテンツ/リサーチ — 読書、執筆、実験、ドキュメント
  4. 外部関係者への質問 — チーム外の特定の人物や企業に確認するトピック
  5. 探索/ツール — ツールの評価、セットアップ、環境に関するタスク
  6. キャッチアップ — 明示的に中断または見落としが認められた事項
出力形式

1 人の人物モード:

# [Name] Synthesized Notes — [Meeting Title]

**Date:** [Date]
**Fireflies Link:** https://app.fireflies.ai/view/[TRANSCRIPT_ID]

## [Category Name]

- **Item title**
  - Context, decisions, and full detail
  - > "Exact quote"

全参加者モード:

# Synthesized Notes — [Meeting Title]

**Date:** [Date]
**Fireflies Link:** https://app.fireflies.ai/view/[TRANSCRIPT_ID]

## [Person Name]

### [Category Name]

- **Item title**
  - Context, decisions, and full detail
  - > "Exact quote"

フェーズ 5:Linear チケットの提案

統合ノートから、Linear チケットの作成と更新を導き出します。フェーズ 4 の詳細な背景と引用は、コメントまたはチケットの説明として Linear に反映し、Linear を信頼できる情報源とします。設定ファイルでチームのデフォルトを指定し、更新候補を探すために進行中サイクルのチケットを取得します。

5a: 設定の解決

チーム設定を次の順序で探します(最初に一致したものを使用します)。

  1. ~/.agents/configs/extract-my-action-items/config.json(ユーザーによる上書き)
  2. references/config.json(このスキルファイルを基準とする、同梱のデフォルト設定)

ユーザー設定が見つかった場合は、それを使用します。見つからない場合は、同梱の config.json にフォールバックします。

ユーザー設定が存在せず、かつ同梱の設定の team フィールドが空の場合は、停止してユーザーに確認してください。

Linear の設定が見つかりません。ユーザー設定を次の場所に作成してください:~/.agents/configs/extract-my-action-items/config.json

同梱の references/config.json をひな形としてコピーし、チーム、プロジェクト、担当者、ラベルを入力してください。

設定が正常に解決されたら、続行します。

5b–5c: アクティブなチケットの取得とセマンティックマッチング(単一のサブエージェント)

重要:5b と 5c は、単一の general-purpose サブエージェント内でまとめて実行してください。 サイクルのチケットデータは大きいため、メインのコンテキストウィンドウに流さないでください。

次のプロンプトでサブエージェントを起動します。

## Task: Pull active Linear tickets and match against synthesized meeting notes

### Step 1: Pull active tickets

Config: team=[TEAM], states=[STATES_LIST], attendees=[SPEAKER_LIST]

1. `mcp__linear__list_teams` with query=[TEAM] → get team ID
2. `mcp__linear__list_cycles` with type="current" → get current cycle ID
3. In parallel:
   - `mcp__linear__list_issues` filtered by cycle + team (limit 250)
   - `mcp__linear__list_issues` for each attendee (assignee filter, state="In Progress")
4. Deduplicate and build a lookup table: {identifier, title, assignee, status}

### Step 2: Semantic matching

Read the synthesized notes at [SYNTHESIZED_NOTES_PATH].

For each item, classify as:
- **UPDATE [TICKET-ID]** — maps to an existing ticket. Explain what new info to append.
- **NEW TICKET** — distinct deliverable not covered. Suggest title, assignee, priority.
- **IDEA** — process improvement, behavioral commitment, or exploratory thought.

Group output by classification. For UPDATE items include ticket ID. For NEW TICKET items include suggested title, assignee, and priority.
5d: スクラッチパッドに提案を下書きする

references/ticket-template.md のテンプレートを使用して、.claude/scratchpad/linear-proposals-YYYY-MM-DD.md に書き込みます。

  • 更新の提案: UPDATE に一致した項目ごとに、新しいフィードバックを記載したコメント本文を下書きします(合成したメモからの文脈と引用を含む日付付きのセクション)。課題の説明は変更しないでください。更新はコメントとして投稿します。
  • 新規チケットの提案: 合成したメモからの具体例と正確な引用を含め、send-to-linear の説明形式(User Story、Requirements、Acceptance Criteria)を使用します。
  • アイデア/さらに検討が必要な項目: 人物、文脈、正確な引用を記載します。これらは省略せず、提案ファイルには含めますが、完全なチケットにはしません。
5e: ユーザーレビューの確認

停止してください。 提案ファイルの準備ができたことと、その保存先が .claude/scratchpad/linear-proposals-YYYY-MM-DD.md であることをユーザーに伝え、明示的な指示を待ちます。

AskUserQuestion を使用します。「Linear チケットの提案を用意しました。ファイルを確認して、次を選択してください:」

  • 「Linear でチケットを作成/更新する」— 実行に進む
  • 「スキップ — Slack の DM のみ実行する」— Phase 7 に進む

ユーザーは承認前にスクラッチパッドファイルを編集できます。承認されたら:

  1. Linear MCP を使用してチーム ID、ラベル ID、プロジェクト ID、現在のサイクルを解決します(send-to-linear の Phase 6 と同じパターンです)。
    • mcp__linear__list_teams → チーム ID
    • mcp__linear__list_issue_labels → ラベル ID
    • mcp__linear__list_projects → プロジェクト ID(設定されている場合)
    • mcp__linear__list_cycles(type: "current" を指定)→ 現在のサイクル
  2. 更新の場合: issueId と下書きしたコメント本文を指定して mcp__linear__create_comment を使用します。説明を変更するために mcp__linear__save_issue を使用しないでください。
  3. 新規チケットの場合: 設定と提案からすべてのフィールド(チーム、プロジェクト、担当者、サイクル、状態、ラベル、タイトル、説明)を指定して mcp__linear__save_issue を使用します。
  4. アイデア: Linear での操作は行いません(参照用として提案ファイルに残します)。
  5. ユーザーが確認できるよう、クリック可能なリンクを付けて結果を報告します。
    • 更新したチケット: コメントを追加したチケットごとに https://linear.app/[WORKSPACE]/issue/[TICKET-ID]
    • 作成したチケット: 新規チケットごとに https://linear.app/[WORKSPACE]/issue/[TICKET-ID](save_issue が返した識別子を使用)
    • [WORKSPACE] はチームの組織キー、または設定から取得します。

Phase 6: アクションアイテムのチェックリスト

合成したメモをもとに、簡潔なアクションアイテムのチェックリストを作成します。詳細の正本は Linear です。チェックリストは、リンク付きで一覧しやすくするためのものです。

項目が Linear のチケット(Phase 5 で更新または作成したもの)に対応する場合は、その Linear リンクを項目内に含めます。Linear に送らない項目は、1 行の説明のみを記載します。

出力

単一人物モード — .claude/scratchpad/[name]-action-items-YYYY-MM-DD.md に書き込みます。

# [Name] Action Items — [Meeting Title]

**Date:** [Date]
**Fireflies Link:** https://app.fireflies.ai/view/[TRANSCRIPT_ID]

## [Category Name]

- [ ] **Item title** — [TICKET-ID](https://linear.app/[WORKSPACE]/issue/[TICKET-ID])
- [ ] **Item without ticket** — brief context

全出席者モード — .claude/scratchpad/action-items-YYYY-MM-DD.md に書き込みます。

# Action Items — [Meeting Title]

**Date:** [Date]
**Fireflies Link:** https://app.fireflies.ai/view/[TRANSCRIPT_ID]

## [Person Name]

### [Category Name]

- [ ] **Item title** — [TICKET-ID](https://linear.app/[WORKSPACE]/issue/[TICKET-ID])
- [ ] **Item without ticket** — brief context

## Quick Reference — Time-Sensitive

1. [Person] — [Item with deadline]

各項目は 1 行に収めてください。

フェーズ 7:確認と Slack への DM 送信

  1. AskUserQuestion を使用して、「各メンバーに Slack でアクションアイテムを DM で送信しますか?」 と尋ねます。選択肢は「DM を送信」「スキップ — ファイルのみ保持」です。
  2. 承認された場合、プロジェクトのルートに .claude/slack-users.local.json が存在することを確認します。
    • 存在しない場合は、node [SKILL_DIR]/scripts/fetch-slack-users.mjs を実行します(users:read スコープを持つ SLACK_BOT_TOKEN が必要です)。出力をユーザーに提示して確認してもらった後、.claude/slack-users.local.json に保存します(**/.claude/**/*.local.json によって Git の追跡対象から除外されます)。
    • 存在する場合は、そのまま続行します。
  3. 出力ファイルのパスを指定して、同梱のスクリプトを実行します。
node [SKILL_DIR]/scripts/slack-post.mjs [OUTPUT_FILE_PATH]

スクリプトは conversations.open と chat.postMessage を使用して、Block Kit 形式の DM を各メンバーに送信します。環境変数 SLACK_BOT_TOKEN(chat:write および im:write スコープ付き)が必要です。

モードごとの動作:

  • 全出席者: slack-users.local.json で一致した各メンバーに、自分のアクションアイテムのみを含む DM が送信されます。名前を解決できない場合は、警告を表示してスキップします。
  • 単一メンバー: 対象者に DM を 1 件送信します。

名前の解決では、完全一致と名のあいまい一致(例:「Jelvin」は「Jelvin Base」に一致)に対応しています。スクリプトの実行後、スキップされた名前があればユーザーに報告します。

  1. 投稿後(またはスキップ後)、実行中に作成されたすべての成果物を削除します。対象は transcript.txt、synthesized-notes-YYYY-MM-DD.md、アクションアイテムの Markdown ファイル、linear-proposals-YYYY-MM-DD.md、およびこのワークフロー中に .claude/scratchpad/ に書き込まれたその他の一時ファイルです。

呼び出し例

  • /extract-my-action-items — 全出席者、直近の会議
  • /extract-my-action-items standup — 全出席者、「standup」を検索
  • /extract-my-action-items for Basti from yesterday — 単一メンバー
  • /extract-my-action-items 01KFY1RSEVVQW7MB1TKG4N2D20 — 全出席者、特定のトランスクリプト

コメント