Skip to content
Documentation
Command

/start-11-3

Lesson command

From plugin
ai-agent-camp
345200 skills8 agents200 commands
Install
$ npx -y skills add minicoohei/ai-agent-camp --agent claude-code

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/start-11-3

Context preview

What this command does when you run it.

Lesson command

Command definition

start-11-3.md
description: "Lesson command"
chapter: "courses/aiagent/lesson03-core/module11-github-actions"
duration: "約25分"
prerequisites: ["start-11-2"]
level: "intermediate"
tags: ["github-actions", "news", "email", "slack", "webhook", "cron"]
nonInteractiveMode: incompatible

🎓 Lesson 11-3: ニュース取得→メール/Slack配信ワークフロー

📍 このセッションでやること

**Lesson 11-3: ニュース取得→メール/Slack配信** へようこそ!

| 項目 | 内容 | |------|------| | ゴール | GitHub Actions でニュースを自動取得し、メールと Slack に配信するワークフローを構築する | | 所要時間 | 約25分 | | 使うスキル | GitHub Actions, Python (requests), Slack Webhook, smtplib | | 前提条件 | Lesson 11-2 完了(Secrets 設定の理解) |

**このセッションの流れ:** 1. ニュース取得スクリプトの作成 2. メール送信処理の実装 3. Slack Webhook 通知の設定 4. GitHub Actions ワークフロー作成 5. Secrets 設定と動作テスト

セッション終了時には、定期的にニュースを収集してメールと Slack に自動配信するパイプラインが完成しています。

> **💡 ヒント**: AIの応答が途中で止まった場合は「続きを表示して」「止まってるよ」と入力すると再開します。

---

🎯 準備チェック

**AskQuestionの設定:**

{
  "title": "🎯 セッション開始前の確認",
  "questions": [{
    "id": "readiness",
    "prompt": "準備はできていますか?",
    "options": [
      {"id": "ready", "label": "準備OK!始めましょう"},
      {"id": "check_prereq", "label": "前提条件を確認したい"},
      {"id": "different_lesson", "label": "別のレッスンに移動したい"}
    ]
  }]
}

(ready → Step 1へ) (check_prereq → Lesson 11-2 完了確認。`.github/workflows/` ディレクトリの存在確認) (different_lesson → モジュール一覧を表示)

---

🚀 Step 1: ニュース取得スクリプトの作成

{
  "title": "🚀 Step 1: ニュース取得スクリプト",
  "questions": [{
    "id": "step_action",
    "prompt": "RSS フィードまたは News API からニュースを取得する Python スクリプトを作成します。",
    "options": [
      {"id": "practice", "label": "このまま進める"},
      {"id": "review", "label": "RSS/API の仕組みを確認"},
      {"id": "skip", "label": "スキップ"}
    ]
  }]
}

**選択後の案内(例)**:

`tools/fetch_news.py` を作成:

#!/usr/bin/env python3
"""ニュース取得スクリプト — RSS フィードからニュースを収集"""
import json
import xml.etree.ElementTree as ET
from datetime import datetime
import requests

# RSS フィード URL(例: はてなテクノロジー)
RSS_FEEDS = [
    {"name": "Hacker News", "url": "https://hnrss.org/newest?count=5"},
    {"name": "TechCrunch", "url": "https://techcrunch.com/feed/"},
]

def fetch_rss(url, max_items=5):
    """RSS フィードからニュース取得"""
    resp = requests.get(url, timeout=30)
    resp.raise_for_status()
    root = ET.fromstring(resp.text)
    items = []
    for item in root.iter("item"):
        title = item.findtext("title", "")
        link = item.findtext("link", "")
        pub_date = item.findtext("pubDate", "")
        items.append({"title": title, "link": link, "pubDate": pub_date})
        if len(items) >= max_items:
            break
    return items

def main():
    all_news = []
    for feed in RSS_FEEDS:
        try:
            items = fetch_rss(feed["url"])
            all_news.append({"source": feed["name"], "items": items})
        except Exception as e:
            print(f"[WARN] {feed['name']}: {e}")
    
    # JSON 出力
    output = {
        "generated_at": datetime.utcnow().isoformat(),
        "feeds": all_news
    }
    with open("output/news_digest.json", "w") as f:
        json.dump(output, f, ensure_ascii=False, indent=2)
    print(f"取得完了: {sum(len(f['items']) for f in all_news)} 件のニュース")
    return output

if __name__ == "__main__":
    main()
mkdir -p output && python tools/fetch_news.py

**期待される結果**: `output/news_digest.json` にニュースデータが保存される。

---

🚀 Step 2: メール送信処理の実装

{
  "title": "🚀 Step 2: メール送信",
  "questions": [{
    "id": "step_action",
    "prompt": "取得したニュースをメールで送信する処理を追加します。",
    "options": [
      {"id": "practice", "label": "このまま進める"},
      {"id": "review", "label": "smtplib の使い方を確認"},
      {"id": "skip", "label": "スキップ"}
    ]
  }]
}

**選択後の案内(例)**:

`tools/fetch_news.py` に送信関数を追加:

import smtplib
from email.mime.text import MIMEText
import os

def send_email(news_data):
    """ニュースダイジェストをメール送信"""
    smtp_user = os.environ.get("SMTP_USER", "")
    smtp_pass = os.environ.get("SMTP_PASS", "")
    to_email = os.environ.get("NOTIFY_EMAIL", smtp_user)
    
    if not smtp_user or not smtp_pass:
        print("[SKIP] SMTP 認証情報が未設定のため、メール送信をスキップ")
        return

    # メール本文作成
    body_lines = [f"# ニュースダイジェスト ({news_data['generated_at'][:10]})\n"]
    for feed in news_data["feeds"]:
        body_lines.append(f"\n## {feed['source']}")
        for item in feed["items"]:
            body_lines.append(f"- [{item['title']}]({item['link']})")
    
    body = "\n".join(body_lines)
    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = f"ニュースダイジェスト {news_data['generated_at'][:10]}"
    msg["From"] = smtp_user
    msg["To"] = to_email

    with smtplib.SMTP("smtp.gmail.com", 587) as server:
        server.starttls()
        server.login(smtp_user, smtp_pass)
        server.send_message(msg)
    print(f"メール送信完了: {to_email}")

**ポイント**: Gmail の場合、アプリパスワードが必要。Secrets に `SMTP_USER` と `SMTP_PASS` を設定する。

**期待される結果**: ニュースダイジェストがメールで送信される。

---

🚀 Step 3: Slack Webhook 通知の設定

{
  "title": "🚀 Step 3: Slack 通知",
  "questions": [{
    "id": "step_action",
    "prompt": "Slack Incoming Webhook でニュース通知を送信します。",
    "options": [
      {"id": "practice", "label": "このまま進める"},
      {"id": "review", "label": "Slack Webhook の作成方法を確認"},
      {"id": "skip", "label": "スキップ"}
    ]
  }]
}

**選択後の案内(例)**:

def send_slack(news_data):
    """Slack Webhook でニュース通知"""
    webhook_url = os.environ.get("SLACK_WEBHOOK", "")
    if not webhook_url:
        print("[SKIP] SLACK_WEBHOOK が未設定のため、Slack 通知をスキップ")
        return

    # Slack メッセージ構築
    blocks = [{"type": "header", "text": {"type": "plain_text", "text": "📰 ニュースダイジェスト"}}]
    for feed in news_data["feeds"]:
        items_text = "\n".join(f"• <{i['link']}|{i['title']}>" for i in feed["items"])
        blocks.append({
            "type": "section",
            "text": {"type": "mrkdwn", "text": f"*{feed['source']}*\n{items_text}"}
        })

    payload = {"blocks": blocks}
    resp = requests.post(webhook_url, json=payload, timeout=10)
    resp.raise_for_status()
    print("Slack 通知送信完了")

**W

Read more
Ships withai-agent-camp

AI Agent Training for Non-Engineers - Complete Guide to Claude Code / Cursor / Codex ### ⚠️ Before you clone Official repository (maintained by the authors): Running AI agents from this repo grants them shell, file-write, and external-API permissions on your

Get the whole plugin