ai-talks-monitor
Monitors YouTube for new long-form original talks and interviews with AI thought leaders. Use this skill whenever the user asks about new AI talks or interviews, says things like "any new Sam Altman talks?", "check YouTube for new AI interviews", "run the talks monitor", "who's on the watchlist?", "add [name] to the watchlist", or wants to manage, schedule, or configure the AI talks monitor. Also use when the user wants to set up automated YouTube monitoring, integrate AI talk discovery with Telegram, Feishu, OpenClaw, or an RSS reader, or enable org-based searches for conference keynotes or unknown speakers. Filters out derivative content (reactions, summaries, explainers) using LLM classification. Writes RSS 2.0 feeds and optionally sends a chat notification.
git clone https://github.com/linzzzzzz/ai-talks-monitor-skill
git clone --depth=1 https://github.com/linzzzzzz/ai-talks-monitor-skill ~/.claude/skills/linzzzzzz-ai-talks-monitor-skill-ai-talks-monitor
SKILL.mdAI Talks Monitor
Watches YouTube for new long-form original talks and interviews featuring AI thought leaders. The script handles YouTube search and state; you handle the classification step.
Supports three modes:
- Person watchlist (default): tracks specific people across any channel they appear on
- Org search (opt-in): catches lab insiders and researchers not on the person watchlist, using org-confirmation to filter noise
- Channel watchlist (opt-in): monitors specific high-signal channels for any AI talk
Setup
-
Set environment variables:
— YouTube Data API v3 key (free; get from Google Cloud Console)YOUTUBE_API_KEY
— Telegram bot token (optional; only forTELEGRAM_BOT_TOKEN
. Also setnotifications.backend: "native"
innative.target
)config.yaml
— absolute path to a local git repo (optional; if set,AI_TALKS_FEEDS_REPO
copies RSS feeds there and pushes automatically)--commit-file
-
Install Python dependencies:
pip install requests pyyaml yt-dlp
Usage
Check for new talks now
This is a four-phase process: the script fetches candidates, you classify them in smaller batches, the script prepares an accepted-items draft, then you enrich only those accepted items before commit.
Phase 1 — fetch candidates from YouTube:
python3 SKILL_DIR/scripts/check_talks.py --fetch-candidates
Do NOT add
--lookback-days unless the user explicitly asks to backfill a longer period. The default rolling window in config.yaml is correct for normal runs.
Phase 2 — classify candidates (subagent parallel):
The
--fetch-candidates output ends with a CLASSIFICATION PLAN listing candidate files grouped by category. Spawn up to 3 subagents in parallel — one each for people, orgs, and channels.
- OpenClaw: use
(withsessions_spawn
)runTimeoutSeconds: 480 - Claude Code: use the
tool (withAgent
,model: "sonnet"
)run_in_background: true
Do NOT read any
files yourself. The subagents will read them. You only need the reference files below.candidates_*.json
Step 1 — read reference context. Before spawning, read these files yourself so you can include their content in each subagent task:
— classification rulesSKILL_DIR/CLASSIFY.md
(if it exists) —SKILL_DIR/output/state.json
array for cross-run deduplicationitems- All ephemeral files (candidates, reviews, enrichment, accepted) live under
, which is wiped at the start of eachoutput/scratch/
run.--fetch-candidates
is NOT needed — theSKILL_DIR/config.yaml
field is already baked into each org candidateorg
Step 2 — spawn one subagent per category. For each category listed in the CLASSIFICATION PLAN, spawn a subagent with this task:
Classify AI talk candidates for the "{category}" category. Read ALL candidate files listed below, apply the classification rules, and write the review file. CANDIDATE FILES (read every file — each is ≤15 items): {list all chunk files for this category, e.g.: - SKILL_DIR/output/scratch/candidates_orgs_1.json - SKILL_DIR/output/scratch/candidates_orgs_2.json - SKILL_DIR/output/scratch/candidates_orgs_3.json - SKILL_DIR/output/scratch/candidates_orgs_4.json} REVIEW FILE: SKILL_DIR/output/scratch/review_{category}.json CLASSIFICATION RULES: {paste full CLASSIFY.md content here} STATE ITEMS (for deduplication): {paste state.json items array here, or "none" if empty} OUTPUT FORMAT — write the review file as valid JSON: { "source": "scratch/candidates_{category}", "candidates_reviewed": <total items across ALL files above>, "accepted": [ {"id": "VIDEO_ID", "reason": "one sentence: why this meets the acceptance criteria (e.g. which person is confirmed as speaker, or which org affiliation was verified)"} ], "rejected": ["VIDEO_ID_1", "VIDEO_ID_2"], "uncertain": ["VIDEO_ID_3"] } RULES: - Read ALL candidate files listed above. Do not skip any file. - Every candidate must appear in accepted, rejected, or uncertain. - The "reason" field is required for each accepted item. - candidates_reviewed must equal the total items across all files. - Use "uncertain" for candidates with insufficient information (empty description, ambiguous title). These will NOT be written to state.json and will resurface on the next run.
Step 3 — wait and merge. After all subagents complete, read each
output/scratch/review_{category}.json file and merge into SKILL_DIR/output/scratch/review.json:
{ "accepted": [{"id": "VIDEO_ID_A", "reason": "..."}, {"id": "VIDEO_ID_B", "reason": "..."}], "rejected": ["VIDEO_ID_1", "VIDEO_ID_2", "VIDEO_ID_3"], "uncertain": ["VIDEO_ID_4"] }
IDs in
uncertain are left unmarked in state and will reappear on the next run.
Phase 3 — prepare accepted items for enrichment:
python3 SKILL_DIR/scripts/check_talks.py --prepare-accepted SKILL_DIR/output/scratch/review.json
This writes
SKILL_DIR/output/scratch/accepted.json with only the accepted candidates plus their original metadata.
Now read
output/scratch/accepted.json and generate an enrichment file. For each accepted video, write only the generated fields to SKILL_DIR/output/scratch/enrichment.json:
[ { "id": "VIDEO_ID_A", "description_clean": "...", "title_zh": "...", "description_zh": "..." } ]
Field guidelines:
: a cleaned version of the video description in its original language. Base it only on available metadata (title, channel, description). Remove links, sponsor boilerplate, social handles, calls to action. Keep useful structure like chapter/timestamp breakdowns. If the source description is sparse, write a short conservative blurb rather than inventing details.description_clean
: a concise, natural Chinese translation of the title (not literal word-for-word)title_zh
: a Chinese translation ofdescription_zh
, written for a Chinese-speaking audience. Do not add information not present in the metadata.description_clean
Important: Use Chinese-style quotation marks
「」 instead of ASCII " inside Chinese text to avoid breaking JSON.
Then apply the enrichment:
python3 SKILL_DIR/scripts/check_talks.py --apply-enrichment SKILL_DIR/output/scratch/enrichment.json
This merges your generated fields into
accepted.json. It will reject the enrichment if any accepted items are missing or have empty fields.
Phase 4 — commit accepted videos:
You MUST use
--commit-file (not --commit). Only --commit-file publishes the enriched Chinese translations and cleaned descriptions.
python3 SKILL_DIR/scripts/check_talks.py --commit-file SKILL_DIR/output/scratch/accepted.json
This writes both
ai_talks.xml (English) and ai_talks_zh.xml (Chinese titles and translated descriptions), updates state.json, sends a notification if configured, and pushes to the feeds repo if AI_TALKS_FEEDS_REPO is set.
Note:
--commit-file will refuse to publish any item missing a published_at date (can happen with yt-dlp metadata fallback). If this occurs, re-run --fetch-candidates with YOUTUBE_API_KEY set and backends.metadata: youtube_api, or set ytdlp_search.cookies_from_browser in config.yaml, then retry.
Use
--dry-run to preview without writing files or updating state:
python3 SKILL_DIR/scripts/check_talks.py --commit-file SKILL_DIR/output/scratch/accepted.json --dry-run
After committing, report what was accepted to the user.
Add a person to the watchlist
Edit
SKILL_DIR/config.yaml and add an entry under thought_leaders:
- name: "[Full Name]" search_query: '[Full Name]'
For bilingual subjects, add a second entry with their native name:
- name: "Fei-Fei Li (Chinese)" search_query: '李飞飞'
Confirm the addition to the user.
Remove from watchlist
Edit
SKILL_DIR/config.yaml and remove the relevant entry from thought_leaders.
Enable org-based searches
Edit
SKILL_DIR/config.yaml, set orgs.enabled: true, and add entries under orgs.searches:
orgs: enabled: true searches: - name: "Anthropic Talks" search_query: 'anthropic researcher talk podcast' org: "Anthropic" min_duration_minutes: 20
Org searches are noisier than person searches — a higher
min_duration_minutes helps.
Show current watchlist
Read and display
thought_leaders, channels.list (if enabled), and orgs.searches (if enabled) from SKILL_DIR/config.yaml.
Adjust settings
— minimum video length to consider (default: 20). Raise to cut more noise.min_duration_minutes
— rolling search window in days (default: 5). Every run searches this far back.lookback_days
—backends.search
,auto
, oryoutube_api
. Useyt_dlp
to save quota on discovery searches.yt_dlp
—backends.metadata
,auto
, oryoutube_api
. A good hybrid setup isyt_dlp
plussearch: yt_dlp
.metadata: youtube_api
— whenytdlp_search.use_this_week_filter
uses yt-dlp, apply a YouTube-side "This week" prefilter before local date filtering (default:backends.search
). Surfaces fresh uploads that yt-dlp's default relevance ranking misses; local date filtering remains the authoritative cutoff either way.true
— browser to pull cookies from when a yt-dlp backend is used (ytdlp_search.cookies_from_browser
,chrome
, orfirefox
; default:safari
). Set this if yt-dlp hits YouTube bot-checks or if you want yt-dlp metadata fallback to fetch full descriptions.""
—notifications.backend
,telegram
, oropenclawnone
/notifications.openclaw.channel
/notifications.openclaw.target
— used when routing notifications through OpenClaw, including Feishu supportnotifications.openclaw.account
Automated Daily Check
The fetch step can be scheduled unattended —
--fetch-candidates only writes candidate files and never modifies state, so it's safe to run on a timer. The review/prepare/commit steps happen via the skill when you review.
macOS (launchd) — runs even after reboots:
# Create ~/Library/LaunchAgents/com.openclaw.ai-talks-monitor.plist # then: launchctl load ~/Library/LaunchAgents/com.openclaw.ai-talks-monitor.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key><string>com.openclaw.ai-talks-monitor</string> <key>ProgramArguments</key> <array> <string>/usr/bin/python3</string> <string>SKILL_DIR/scripts/check_talks.py</string> <string>--fetch-candidates</string> </array> <key>StartCalendarInterval</key> <dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer></dict> <key>EnvironmentVariables</key> <dict> <key>YOUTUBE_API_KEY</key><string>YOUR_KEY_HERE</string> </dict> </dict> </plist>
Linux/cron — runs daily at 9am:
0 9 * * * YOUTUBE_API_KEY=your_key python3 SKILL_DIR/scripts/check_talks.py --fetch-candidates
How it works
- YouTube search (
): Runs three source types — person watchlist (keyword search via API/yt-dlp), channel watchlist (channel feed via API with--fetch-candidates
or yt-dlp withchannelId
), org searches (keyword search). All use a rolling@handle
window.lookback_days - Heuristic pre-filter (
): Rejects titles containing "reaction", "summary", "explained", "breakdown", "解读", "总结", "面试", etc. Wipes--fetch-candidates
, then writes survivors to grouped candidate files thereoutput/scratch/ - Classification (you): Read
+ the grouped candidate files inoutput/state.json
; decide which are genuine original talks, deduplicating same-event uploads both within candidates and against already-committed items. Write decisions tooutput/scratch/output/scratch/review.json - Accepted-item enrichment (you): Run
, write--prepare-accepted
withoutput/scratch/enrichment.json
,description_clean
,title_zh
, then rundescription_zh--apply-enrichment - Commit (
): Builds feeds with a rolling 30-day RSS window, updates--commit-file accepted.json
, sends a notification if configuredstate.json
TrendRadar integration
Both feeds are written on every
--commit-file run. Add either or both to TrendRadar's config/config.yaml:
rss: feeds: - id: "ai-talks" name: "AI Thought Leader Talks" url: "file:///path/to/skills/ai-talks-monitor/ai_talks.xml" max_age_days: 30 enabled: true - id: "ai-talks-zh" name: "AI大咖讲座精选" url: "file:///path/to/skills/ai-talks-monitor/ai_talks_zh.xml" max_age_days: 30 enabled: true
Files
— this fileSKILL.md
— main script:scripts/check_talks.py
,--fetch-candidates
,--prepare-accepted
,--apply-enrichment--commit-file
— watchlist and settings (edit this to customize)config.yaml
— persistent: seen video IDs, last_checked timestamp, rolling item listoutput/state.json
— persistent: auto-generated RSS 2.0 feed (English)output/ai_talks.xml
— persistent: auto-generated RSS 2.0 feed (Chinese titles and translated descriptions)output/ai_talks_zh.xml
— ephemeral per-run directory, wiped at the start of eachoutput/scratch/
:--fetch-candidates
— full candidate dumpcandidates.json
/candidates_people[_N].json
/candidates_orgs[_N].json
— chunked candidate files (≤15 items each)candidates_channels[_N].json
— merged classification decisionsreview.json
— per-subagent classification outputreview_{category}.json
— LLM-generated fields (description_clean, title_zh, description_zh)enrichment.json
— built byaccepted.json
, enriched by--prepare-accepted
, input to--apply-enrichment--commit-file