# Yt Replier

> Manage and reply to YouTube comments on your channel via the official YouTube Data API v3. Monitors recent uploads for unreplied comments, auto-drafts Skool-link replies for keyword CTAs, and posts approved replies. Self-contained (own OAuth token, own data dir). Trigger phrases - "youtube comments", "yt comments", "reply to youtube comments", "check youtube comments", "youtube comment inbox", "yt replies", "youtube unreplied", "respond on youtube".

- Skill: `tylerprogramming/yt-replier` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add tylerprogramming/yt-replier`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tylerprogramming/yt-replier/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: tylerprogramming (https://skillmd.com/u/tylerprogramming)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tylerprogramming/yt-replier

---


# 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-ssl` scope). Reuses `~/credentials.json` client, caches token in `token.json` next to it. Run `python3 auth_yt.py` to authorize, `--reauth` to redo.
- `monitor_yt.py` — fetches recent uploads, finds unreplied top-level comments, splits new ones into `data/inbox_yt.json` (manual) + `data/drafts_queue_yt.json` (auto keyword CTAs). Cron-friendly.
- `queue_draft_yt.py` — moves a drafted reply from `inbox_yt.json` → `drafts_queue_yt.json`.
- `reply_yt.py` — posts each reply in a queue via `comments().insert`, tracks done in `data/posted_yt.json`. Dry-run by default; `--post` to 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"

1. Read `data/inbox_yt.json` (manual-needed) AND `data/drafts_queue_yt.json` (auto-drafts pending).
2. Show the user the breakdown — count of each plus the actual text of inbox items.
3. He picks one or all to draft replies for.

### When the user asks "draft a reply for the @username one"

1. Read the inbox entry for that comment.
2. Compose a reply in your tone (casual, helpful, drives to skool.com/the-ai-agency when relevant). Use `/harut` for conversion-sensitive wording. No em dashes.
3. Show the user the draft, get approval.
4. When approved, run:
   ```
   python3 ~/.claude/skills/yt-replier/queue_draft_yt.py --cid <cid> --reply "<text>"
   ```
   This appends to `drafts_queue_yt.json` AND removes from `inbox_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 1` on 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.json` tracks 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`.

