Skip to content
Documentation
Command

/start-11-3.en

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.en

Context preview

What this command does when you run it.

Lesson command

Command definition

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

๐ŸŽ“ Lesson 11-3: News Fetching โ†’ Email/Slack Distribution Workflow

๐Ÿ“ What You'll Do

**Lesson 11-3: News Fetching โ†’ Email/Slack Distribution**!

| Item | Details | |------|------| | Goal | Build a GitHub Actions workflow that automatically fetches news and distributes it via email and Slack | | Duration | ~25 min | | Skills used | GitHub Actions, Python (requests), Slack Webhook, smtplib | | Prerequisites | Lesson 11-2 completed (understanding of Secrets configuration) |

**Session flow:** 1. Create the news fetching script 2. Implement email sending 3. Set up Slack Webhook notifications 4. Create the GitHub Actions workflow 5. Configure Secrets and test

By the end of this session, you'll have a complete pipeline that periodically collects news and automatically distributes it to email and Slack.

> **๐Ÿ’ก Hint**: If the AI response stops midway, type "please continue" or "keep going" to resume.

---

๐ŸŽฏ Readiness Check

**AskQuestion configuration:**

{
  "title": "๐ŸŽฏ Pre-session check",
  "questions": [{
    "id": "readiness",
    "prompt": "Are you ready?",
    "options": [
      {"id": "ready", "label": "Ready! Let's start"},
      {"id": "check_prereq", "label": "Check prerequisites"},
      {"id": "different_lesson", "label": "Go to a different lesson"}
    ]
  }]
}

(ready โ†’ Go to Step 1) (check_prereq โ†’ Verify Lesson 11-2 completion. Check that the `.github/workflows/` directory exists) (different_lesson โ†’ Display module list)

---

๐Ÿš€ Step 1: Create the News Fetching Script

{
  "title": "๐Ÿš€ Step 1: News Fetching Script",
  "questions": [{
    "id": "step_action",
    "prompt": "Create a Python script that fetches news from RSS feeds or a News API.",
    "options": [
      {"id": "practice", "label": "Proceed"},
      {"id": "review", "label": "Review how RSS/APIs work"},
      {"id": "skip", "label": "Skip"}
    ]
  }]
}

**Guidance after selection:**

Create `tools/fetch_news.py`:

#!/usr/bin/env python3
"""News fetching script โ€” collects news from RSS feeds"""
import json
import xml.etree.ElementTree as ET
from datetime import datetime
import requests

# RSS feed URLs (e.g., Hacker News, TechCrunch)
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):
    """Fetch news from an RSS feed"""
    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
    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"Fetch complete: {sum(len(f['items']) for f in all_news)} news items")
    return output

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

**Expected result:** News data is saved to `output/news_digest.json`.

---

๐Ÿš€ Step 2: Implement Email Sending

{
  "title": "๐Ÿš€ Step 2: Email Sending",
  "questions": [{
    "id": "step_action",
    "prompt": "Add email sending functionality for the fetched news.",
    "options": [
      {"id": "practice", "label": "Proceed"},
      {"id": "review", "label": "Review how smtplib works"},
      {"id": "skip", "label": "Skip"}
    ]
  }]
}

**Guidance after selection:**

Add a sending function to `tools/fetch_news.py`:

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

def send_email(news_data):
    """Send a news digest email"""
    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 credentials not configured, skipping email")
        return

    # Build email body
    body_lines = [f"# News Digest ({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 Digest {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"Email sent: {to_email}")

**Note**: For Gmail, an app password is required. Set `SMTP_USER` and `SMTP_PASS` in Secrets.

**Expected result:** The news digest is sent by email.

---

๐Ÿš€ Step 3: Set Up Slack Webhook Notifications

{
  "title": "๐Ÿš€ Step 3: Slack Notifications",
  "questions": [{
    "id": "step_action",
    "prompt": "Send news notifications via a Slack Incoming Webhook.",
    "options": [
      {"id": "practice", "label": "Proceed"},
      {"id": "review", "label": "Review how to create a Slack Webhook"},
      {"
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