meeting-task-autopilot ── 議事録かmeeting-task-autopilot ── 議事録から翌朝のSlackまでをLLM+MCPで全自動化する1人法人向けオートパイロット
meeting-task-autopilot
MTGとタスク管理を全自動化するオートパイロット
── 会議の宿題を、脳内RAMから消すための自動操縦システム。
会議が終わった瞬間、その宿題は勝手にタスクDBに溜まる。
翌朝、Slackに今日やることが届く。
スレッドにT-1 完了+ 来週月曜までに資料送ると返信するだけで、
完了処理も新規登録も翌朝までに反映される。
PCを開く必要は、もうない。
---
なぜ作ったか(解決したい課題)
1人法人や小規模チームのオーナーは、複数の顧客・案件を自分の頭の中だけで並走させています。1日3〜5本の会議をこなすうち、こんな状況が常態化します:
- 会議のたびに「これ自分の宿題」「これは相手のボール」を頭の中で判別する
- 議事録はAI Meeting Note等で自動取得できても、そこから「次に自分が動くこと」を切り出す作業が手作業で残る
- タスク管理ツールに書いても、毎朝それを開きにいく動作自体が摩擦になる
- 「相手のボール」の状態が頭に居座り続けて、脳内のメモリリークを起こす
この最後の問題が一番重い。中核要求はシンプル:
「自分のボールじゃない時は、脳内RAMから完全に消したい」
本システムはこれを満たすために、議事録から朝のSlackまでの動線を完全自動化します。
コアバリューを一つだけ選べと言われたら、これです:
Slackのスレッド返信だけで、タスクDBと双方向にやりとりできる。
これを成立させているのが [brief:YYYY-MM-DD] という小さなマーカー発明(後述)です。cron的なバッチを、対話的なエージェントに変える小さな仕掛け。これが本作品の最大の独自性です。
---
使い方デモ(朝のSlackで起きていること)
月曜の朝 07:30、Slackに届くブリーフ:
*朝のブリーフ 2026-05-19 (月)*
*今日の予定*
10:00-11:00 A社定例
14:00-15:00 採用面談
19:00-20:00 ジム
*今日のフォーカス*
1. A社の提案資料を最終確認(10時定例で出す)
2. B社の見積もり修正(金曜までに送る約束)
3. 採用面談の質問項目を見直す
*議事録由来の宿題*
A社(顧客):
`T-1` 提案資料のv3を最終確認 _(A社定例 / 05-16)_
`T-2` 見積もり修正版を送付 _(A社定例 / 05-16)_
B社(顧客):
`T-1` 契約書のレビューコメント返却 _(B社キックオフ / 05-15)_
[brief:2026-05-19]
オーナーは通勤電車で、こうリプライする:
T-1, T-2 完了
A社のT-1 → 来週でいい
+ 木曜までに採用面談のフィードバックを返す
+ 急ぎ:今日中に経費精算
翌朝のブリーフは、それを反映済み:
*朝のブリーフ 2026-05-20 (火)*
...
*処理結果*
T-1, T-2 → 完了として除外
A社のT-1 → 先送りとして除外
+ 木曜までに採用面談のフィードバックを返す → ToDoの通常に追加(期限 05-22)
+ 急ぎ:今日中に経費精算 → ToDoの最優先に追加(期限 05-20)
これだけです。PCも、タスク管理ツールも、開かなくていい。
---
システム全体像
┌────────────────────────────┐
│ AI Meeting Note 等で │
│ Notion議事録DBに自動投入 │
└─────────────┬──────────────┘
│ 15分ごとに polling
▼
┌──────────────────────────────────────────────────┐
│ poll_minutes.py │
│ ・transcriptionブロックを再帰展開 │
│ ・Claude Sonnet で My Turn / Their Turn 判定 │
│ ・抽出ステータスでロック(二重起動回避) │
│ ・dual_property で1ページ作成APIから3関係を同期 │
└─────────────┬────────────────────────────────────┘
│
▼
┌──────────────────────────┐
│ Notion タスクDB │
│ 「ボール状態」select で │
│ My/Their/Snoozed/Done │
│ /Blocked を可視化 │
└─────────────┬────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ morning-brief.sh │
│ ・毎朝 07:30、launchd 起動 │
│ ・Claude Code CLI + MCP で3システム横断 │
│ GoogleCalendar / Notion / Slack │
│ ・前日ブリーフID `[brief:YYYY-MM-DD]` をSlack │
│ 検索 → スレッドリプライから完了/除外/ │
│ 新規追加/昇格 を解釈 │
└─────────────┬────────────────────────────────────┘
│ Incoming Webhook
▼
┌──────────────────────────┐
│ Slack に朝ブリーフ │
└──────────┬───────────────┘
▲
│ スレッド返信するだけで翌朝反映
│
┌──────────┴───────────────┐
│ T-1 完了 │
│ T-3 来週でいい │
│ + 来週月曜までに資料送付 │
└──────────────────────────┘
---
このシステムの3つの核となる工夫
工夫1:[brief:YYYY-MM-DD] マーカーで「Slackを状態ストア化」する小発明
朝ブリーフの末尾に必ず [brief:2026-05-19] のような小文字マーカーを1行付けます。
これは人間には不要に見えますが、翌朝、システム自身がSlack検索クエリとして使うためのものです。
仕組み:
- システムが翌朝、
slack_search_public_and_privateで[brief:前日日付]を検索 - ヒットしたメッセージの thread を取得 → リプライを LLM に解釈させる
- 当日ブリーフから完了タスクを除外したり、新規タスクをToDoファイルに追加したりする
つまり Slack の標準機能(スレッド返信)だけで、ボットコマンドも独自UIも作らずに双方向の対話的タスク操作を実現しています。Slackを「メッセージ配信先」ではなく「状態ストア」として再利用する設計です。
cron的なバッチを、対話的なエージェントに変える小さな発明。
工夫2:「ボール位置」を一級プロパティに昇格、LLMにそれを判定させる
タスクDBに ボール状態 という select プロパティを持たせ、選択肢を 🙋 My Turn / 🤝 Their Turn / ⏸ Snoozed / ✅ Done / 🔴 Blocked の5つに固定しました。
これは GTD(Getting Things Done)の "Waiting For" を一段強くしたもので、「相手のボールは My Turn ビューから物理的に見えなくなる」 ことで、脳内RAMからの追い出しを実現します。
LLMに議事録を渡すとつい「タスクを出してください」と書きがちですが、その結果は人が読み返す前提のリストになります。本システムでは抽出スキーマを以下に固定し、LLMに「ボール位置」を判定させるプロンプト設計にしました:
{
"task_name": "動詞始まりの命令文",
"ball_state": "🙋 My Turn | 🤝 Their Turn",
"counterparty": "参加者から推定した相手の氏名 | null",
"due_date": "YYYY-MM-DD | null",
"priority": "🔴 最優先 | 🟡 高 | 🟢 通常",
"notes": "補足"
}
「事実報告・議論の経過は抽出しない、次に誰かが動く必要があるものだけ」という制約をシステムプロンプトに明文化することで、ダッシュボードがゴミタスクで溢れることを防いでいます。
工夫3:「重要ロジックは自分で書き、横断集約はLLMに任せる」棲み分け
朝ブリーフの生成には Slack / Notion / Google Calendar の3つを横断するアクセスが必要です。
通常ならそれぞれのSDKで認証・API呼び出し・エラーハンドリングを書きますが、本システムは:
claude -pコマンドに自然言語プロンプトで指示するだけ- MCP(Model Context Protocol)経由で接続済みの3つのツールに、Claudeが自律的に問い合わせる
- 出力は Slack mrkdwn 形式の本文1つ
shell 200行弱で済んでいます。一方、議事録抽出側(poll_minutes.py)はコスト・品質・並走耐性が重要なので、こちらはあえて Anthropic SDK 直叩きで実装しました。
コア判断軸:重要なロジックは自分で書く。横断的な情報集約は LLM + MCP に任せる。
「LLMが横断アクセスできる時代に、なぜ自分でSDKラッパーを書くのか?」という問いへの答え。
---
実装上の堅牢性(裏側の地味な工夫)
| 工夫 | 内容 |
|---|---|
| 軽量ロック | 抽出ステータス プロパティを 未処理 → 処理中 に PATCH することで、launchdの並走時の二重起動を回避(厳密なmutexではなく、Notion APIにIf-Match等が無いことを踏まえた実用的な軽量ロック) |
| dual_property の活用 | タスクDBの relation 3つ(関連議事録 / 顧客 / Counterparty)を1ページ作成APIに含めるだけで、議事録側・顧客側・担当者側の逆方向プロパティも自動整合 |
| transcriptionブロックの再帰展開 | AI Meeting Note 固有の transcription ブロックを最大深度6で再帰的に plain text 化、ノイズになる image/embed等はスキップ |
| 指数バックオフリトライ | Notion API の 429 / 5xx / Connection/Timeout/SSL エラーに対し、最大5回の指数バックオフ+Retry-Afterヘッダ尊重 |
| 2.5 req/s スロットル | Notion APIレート制限(3 req/s)に対し保守的に 2.5 req/s で動作、本文取得込みで1議事録あたり数秒 |
| 自然言語の期限ヒント正規化 | リプライ中の「今日中」「明日」「来週月曜」「N月N日」を YYYY-MM-DD に正規化、年補完も自動 |
---
既存ツールとの差別化
| Notion AI | Reclaim / Motion | Sunsama | 本システム | |
|---|---|---|---|---|
| 議事録 → タスク自動切り出し | △(要プロンプト) | × | × | ◎ |
| ボール位置(My/Their)の一級プロパティ化 | × | × | × | ◎ |
| Slackスレッド返信だけで完了/追加 | × | × | × | ◎ |
| 顧客×担当者の関係ネットワーク | × | × | × | ◎(Notion relation活用) |
| サーバーレス(クラウド料金ゼロ) | n/a | × | × | ◎(launchd常駐) |
| カスタマイズ性 | △ | × | × | ◎(自分のNotion構造に合わせて改造可) |
差別化の核は 「議事録→ボール位置タスク化」と「Slack双方向UX」の組み合わせです。
このセットを既存SaaSで実現しようとすると、複数ツールを跨ぐワークフローを自分で組む必要があります。
---
ランニングコスト
| 項目 | 最小構成 | 推奨構成 |
|---|---|---|
| サーバー | 0円(macOS常駐機のlaunchd) | 0円 |
| Notion | 既存プランを流用(追加0円) | Plus $10/月 |
| Slack | 既存ワークスペース(追加0円) | Pro $7.25/月 |
| Anthropic API(議事録抽出) | 30〜100円/議事録(Sonnet) | 同左 |
| Anthropic API(朝ブリーフ) | 数十円/日 | 同左 |
| 月間目安(議事録 20本/月想定) | 約 1,000〜2,500円 | 約 3,000〜5,000円 |
サーバーを立てないので固定費は実質ゼロ。コストはLLM呼び出しの従量分のみで、議事録の本数に比例します。
---
ファイル構成
meeting-task-autopilot/
├── README.md
├── .env.sample # 必須環境変数の雛形(13項目)
├── .gitignore
├── requirements.txt # anthropic / requests / python-dotenv
├── notion_client.py # Notion REST薄ラッパ(429/5xx指数バックオフ)
├── prompts.py # 抽出用 system / user プロンプト
├── poll_minutes.py # 議事録ポーリング本体(15分間隔)
├── scripts/
│ └── morning-brief.sh # 朝ブリーフ生成(毎朝 07:30)
└── launchd/
├── com.example.morning-brief.plist
└── com.example.poll-minutes.plist
| ファイル | 行数 | 役割 |
|---|---|---|
poll_minutes.py | 約400 | 議事録DB→タスクDBの自動化エンジン |
scripts/morning-brief.sh | 約180 | 朝ブリーフ生成(Claude Code CLI + MCPに委譲) |
prompts.py | 約45 | LLM抽出プロンプトを宣言的に管理 |
notion_client.py | 約50 | Notion REST薄ラッパ |
---
Notion DB の前提構造
議事録DB(Meeting Notes)
| プロパティ | 型 | 用途 |
|---|---|---|
| 名前 | title | 議事録タイトル |
| 作成日 | date | 会議日 |
| 顧客 | relation | 顧客リストへの参照 |
| 参加者 | relation | 担当者リストへの参照 |
| 抽出ステータス | select | 未処理 / 処理中 / 完了 / エラー |
| 抽出済みタスク | relation | タスクDBとの dual_property |
タスクDB(Tasks)
| プロパティ | 型 | 用途 |
|---|---|---|
| タスク名 | title | |
| ボール状態 | select | 🙋 My Turn / 🤝 Their Turn / ⏸ Snoozed / ✅ Done / 🔴 Blocked |
| Last Ball Movement | date | 最終更新日(自動セット) |
| Priority | select | 🔴 最優先 / 🟡 高 / 🟢 通常 |
| 完了予定日 | date | |
| 関連議事録 | relation | 議事録DBとの dual_property |
| 顧客 | relation | 顧客リストへの参照 |
| Counterparty | relation | 担当者リストへの参照(誰のボールか) |
推奨ビュー(タスクDB)
- 🙋 Now(My Turn、グループ=顧客)
- 🚨 Stale Their Turn(Their Turn かつ Last Ball Movement が7日以上前、グループ=Counterparty)
- ⏰ Snooze Queue(Snoozed、ソート=Snooze Until)
- 🔴 Blocked(Blocked、グループ=顧客)
- 📅 Recently Done(Done で30日以内、ソート=Last Ball Movement 降順)
- 📊 Client Board(boardビュー、グループ=ボール状態、Done除外)
---
セットアップ
前提
- macOS(launchd利用)/ Linux(cron や systemd timer に読み替え可能)
- Python 3.10+
- Claude Code CLI インストール済み
- 以下をMCPとして接続済み: Slack / Notion / Google Calendar
- Notion Internal Integration を作成し、議事録DB / タスクDB / 担当者DB に接続
- Anthropic API キー
- Slack Incoming Webhook URL
インストール
git clone <this-repo>
cd meeting-task-autopilot
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
mkdir -p ~/.meeting-task-autopilot
cp .env.sample ~/.meeting-task-autopilot/.env
vim ~/.meeting-task-autopilot/.env # 値を埋める
動作確認
# 1件だけdry-runで抽出プロンプト+LLM応答を表示
python poll_minutes.py --dry-run --limit 1
# 1件だけ本実行(タスクDBにページが作られる)
python poll_minutes.py --limit 1
# 朝ブリーフを今すぐ手動実行(Slackに飛ぶ)
bash scripts/morning-brief.sh
launchd 登録
cp launchd/com.example.morning-brief.plist ~/Library/LaunchAgents/
cp launchd/com.example.poll-minutes.plist ~/Library/LaunchAgents/
# パスを自分の環境に合わせて書き換え
vim ~/Library/LaunchAgents/com.example.morning-brief.plist
vim ~/Library/LaunchAgents/com.example.poll-minutes.plist
# 登録
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.morning-brief.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.poll-minutes.plist
---
拡張ロードマップ
- Snooze自動復帰: 朝6時の launchd で
Snooze Until ≤ 今日のタスクを My Turn に戻す - Counterparty 名寄せ: 「◯◯さん」「◯◯」「◯◯チーム」等の表記揺れを fuzzy matching で解決
- Stale Their Turn の自動リマインド生成: 7日以上動きがない相手ボールに対して、追いリマインドのDM下書きを生成
- 議事録ポーリング完了の通知: Slackに「📌 ◯月◯日XX定例から、自分Y件・相手Z件登録」を投稿
- チーム展開:
OWNER_LABELを複数化し、メンバーごとに My Turn ビューを切り替え
---
ライセンス
MIT