/start-11-3
Lesson command
$ npx -y skills add minicoohei/ai-agent-camp --agent claude-codeHow 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.mddescription: "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
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
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
Other commands on ai-agent-camp.
- /check-setup.en
Top-level alias — see lesson/check-setup.en.md for the full body.
Open command - /check-setup.es
Alias de nivel superior — el cuerpo completo está en lesson/check-setup.es.md.
Open command - /check-setup
Top-level alias — see lesson/check-setup.md for the full body.
Open command - /check-security.en
Lesson command
Open command - /check-security.es
Lesson command
Open command - /check-security
Lesson command
Open command

