YouTube Comment Replier
Two-stage pipeline for managing YouTube comments on your channel - mirrors /tiktok-replier, but YouTube has an official API so there is no Playwright. Both reading comments and posting replies go through the YouTube Data API v3.
Fully self-contained: own OAuth token (token.json), own auth module (auth_yt.py), own data/ dir. No dependency on other skills.
Files
auth_yt.py— OAuth (youtube.force-sslscope). Reuses~/credentials.jsonclient, caches token intoken.jsonnext to it. Runpython3 auth_yt.pyto authorize,--reauthto redo.monitor_yt.py— fetches recent uploads, finds unreplied top-level comments, splits new ones intodata/inbox_yt.json(manual) +data/drafts_queue_yt.json(auto keyword CTAs). Cron-friendly.queue_draft_yt.py— moves a drafted reply frominbox_yt.json→drafts_queue_yt.json.reply_yt.py— posts each reply in a queue viacomments().insert, tracks done indata/posted_yt.json. Dry-run by default;--postto publish.data/inbox_yt.json— comments needing manual reply (full metadata: cid, author, text, video_id, video_url, etc).data/drafts_queue_yt.json— replies ready to post.data/posted_yt.json— comment IDs already replied to (prevents double-posting).data/last_seen_yt.json— dedupe state for the monitor.data/drafts_yt.md— human-readable running log.
The hourly cron + manual draft workflow (PRIMARY pattern)
A cron runs monitor_yt.py every hour at :07. It produces three artifacts in data/:
inbox_yt.json— comments needing manual reply. This is what you ask Claude to help draft.drafts_queue_yt.json— auto-drafted Skool-link replies for short keyword CTAs (System / Plan / Skill / Email / Routine / Tools / VFX / schedule / video / workflow). Already ready to post.drafts_yt.md— human-readable running log.
When the user says "any new youtube comments?" / "check my yt inbox"
- Read
data/inbox_yt.json(manual-needed) ANDdata/drafts_queue_yt.json(auto-drafts pending). - Show the user the breakdown — count of each plus the actual text of inbox items.
- He picks one or all to draft replies for.
When the user asks "draft a reply for the @username one"
- Read the inbox entry for that comment.
- Compose a reply in your tone (casual, helpful, drives to skool.com/the-ai-agency when relevant). Use
/harutfor conversion-sensitive wording. No em dashes. - Show the user the draft, get approval.
- When approved, run:
This appends topython3 ~/.claude/skills/yt-replier/queue_draft_yt.py --cid <cid> --reply "<text>"drafts_queue_yt.jsonAND removes frominbox_yt.json.
When the user says "post them"
python3 ~/.claude/skills/yt-replier/reply_yt.py --post
--post is required to actually publish. Without it the script does a dry-run (prints what it would post). 10s spacing between posts.
Standard workflow (manual / first-time)
0. Authorize (one time)
python3 ~/.claude/skills/yt-replier/auth_yt.py
A browser opens, you approve the YouTube scope, token saves to token.json. (The token was migrated from the /yt-upload skill on creation, so this is usually already done.)
1. Fetch unreplied comments
python3 ~/.claude/skills/yt-replier/monitor_yt.py
Scans the 30 most recent uploads, up to 50 top-level comments each. A comment is "unreplied" when it's top-level, not authored by your channel, and you haven't replied in that thread. New ones get split into inbox (manual) vs auto-queue (keyword CTA).
2. Build reply queue
Show the user the unreplied list, confirm wording, then either:
- auto-drafts are already in
drafts_queue_yt.json, or - draft a manual reply and move it with
queue_draft_yt.py(see above).
3. Post the replies
Always dry-run first, then test on 1, then batch:
python3 reply_yt.py # dry-run (shows everything, posts nothing)
python3 reply_yt.py --post --limit 1 # smoke test - post a single reply
python3 reply_yt.py --post # batch (10s pause between each)
To post the auto-drafted keyword CTAs from a specific queue:
python3 reply_yt.py --post --queue ~/.claude/skills/yt-replier/data/drafts_queue_yt.json
Editing the auto-reply behavior
monitor_yt.py holds the auto-draft logic near the top:
SKOOL_LINK_REPLY— the canned reply text for keyword CTAs.KEYWORD_REPLIES— the keyword → reply map (System / Plan / Skill / Email / Routine / Tools / VFX / schedule / video / workflow).draft_reply_for()— comments longer than 60 chars always go to the manual inbox; short ones matching a keyword get auto-drafted.
Safety rules
- Default to dry-run, then
--limit 1on first run of any new queue. - Always show drafts to you before bulk posting (matches
feedback_confirm_before_scheduling.md— confirm before posting even if approved earlier in the session). posted_yt.jsontracks done IDs so re-runs after a crash skip what already worked.- No em dashes in any reply (matches
feedback_no_em_dashes.md). - No automatic re-fetch + re-post loops — you initiate each batch.
Quota
YouTube Data API v3: 10,000 units/day. Per monitor run is ~30-60 units; each posted reply (comments.insert) is 50 units. Plenty of headroom for normal use.
Cron
7 * * * * /Library/Frameworks/Python.framework/Versions/3.12/bin/python3 \
/Users/tylerreed/.claude/skills/yt-replier/monitor_yt.py \
>> /Users/tylerreed/.claude/skills/yt-replier/data/monitor_yt.log 2>&1
This runs at :07 each hour (TikTok monitor runs at :05). The monitor posts a macOS notification with the new-comment count. It never posts replies on its own — posting is always a manual reply_yt.py --post.