The first lesson gave you a method for choosing topics and the second a structure for scripts. Both work on paper. This lesson turns them into a workflow that runs in minutes each morning, and connects the result to your own website so every video also works for your portfolio.
There are two halves:
- Before the video: a Claude Code skill that does the research, scoring and scripting, with sources.
- After the video: a small sync script and React components that show the channel on a Next.js site.
Part 1: a Claude Code skill for the daily planLink to this section
A skill in Claude Code is a folder containing a SKILL.md file: some front matter that says what it's for, then instructions in plain Markdown. Claude loads it when your request matches the description, or when you type its name. It's the right tool for a process you repeat every day, because the rules live in a file instead of in your memory.
The project-level layout looks like this:
your-site/
βββ .claude/
βββ skills/
βββ daily-video/
βββ SKILL.mdA shortened version of mine:
---
name: daily-video
description: Plan today's video: research and score developer topics,
pick one the channel hasn't covered, then write a Short and a matching
long video with titles, description, tags and sources.
---
# Daily video
1. Know what's published: run `npm run youtube:sync`, then list every
video and Short by topic and views. Skip topics already covered.
2. Find 5β8 candidates from the last 14 days, each with 2+ reputable sources.
3. Score each 1β5 on hook, fit, freshness, search, lesson, gap and site link.
Show the table, recommend one, wait for approval.
4. Write content/videos/YYYY-MM-DD-slug/: short.md, long.md, publish.md,
sources.md. Every claim in the scripts must appear in sources.md.
## Rules
- Accuracy first; say "reportedly" when the source does.
- Titles must be true to the video. Curiosity yes, misleading no.
- Never upload anything without approval.Each morning, typing /daily-video (or "plan today's video") in the project runs the whole thing. Claude searches, reads the primary sources, fills in the scoring table, and writes the four files. My part is the decisions: approve the topic, read sources.md, adjust the voice, record or render.
Keep the human checkpoint. The skill stops after the scoring table and waits for a yes. That pause is where you catch a topic that's technically true but wrong for your audience, or a source that doesn't really say what the summary claims.
Why verification belongs in the skillLink to this section
AI research tools are fast at collecting links and slow to notice that two of them disagree. Writing "every claim must appear in sources.md with its URL" into the skill turns fact-checking from a good intention into a file you can review in a minute. On a recent WordPress story, that file is what showed that several secondary sites had the affected version range wrong.
Working with a production folderLink to this section
If you render videos in a separate project (mine has its own brand bible, characters and render templates), tell the skill to read that folder too. It can avoid topics already in production and follow the same style rules, so the plan can be handed straight to whoever makes the video. Treat that folder as read-only from the planning skill, so two processes never edit the same files.
Part 2: show the channel on your Next.js siteLink to this section
Once a video is live, your website should pick it up without you editing any pages. Three pieces do that: a sync script, a lite player, and structured data.
A sync script with no API keyLink to this section
Every YouTube channel has a public Atom feed with its latest uploads:
https://www.youtube.com/feeds/videos.xml?channel_id=YOUR_CHANNEL_IDIt includes each video's ID, title, publish date and description. A build-time Node script can turn it into JSON that your pages import:
// scripts/sync-youtube.mjs (simplified)
import fs from "node:fs";
const FEED = "https://www.youtube.com/feeds/videos.xml?channel_id=UCxxxxxxxxxxxxxxxxxxxxxx";
const OUT = "src/data/youtube.json";
const decode = (s) => s.replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'");
try {
const res = await fetch(FEED, { signal: AbortSignal.timeout(15000) });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const xml = await res.text();
const videos = xml.split("<entry>").slice(1).map((e) => ({
id: e.match(/<yt:videoId>([^<]+)/)[1],
title: decode(e.match(/<title>([^<]+)/)[1]),
published: e.match(/<published>([^<]+)/)[1],
isShort: /\/shorts\//.test(e.match(/<link rel="alternate" href="([^"]+)"/)[1]),
}));
fs.writeFileSync(OUT, JSON.stringify({ syncedAt: new Date().toISOString(), videos }, null, 2));
console.log(`β ${videos.length} videos`);
} catch (err) {
// Never break the build: keep the last good file.
console.warn(`β YouTube sync skipped (${err.message}); using the existing ${OUT}`);
}Two details matter. The isShort flag comes from the entry's link, which points to /shorts/ for Shorts. And the catch keeps the previous JSON when YouTube is unreachable, so a network blip never fails a deploy.
The feed only lists the most recent uploads (around fifteen). If you need your whole back catalogue, the official YouTube Data API returns everything, but needs an API key and a quota. For a personal site, the feed plus a committed JSON file is usually enough.
Run it before every build:
{
"scripts": {
"youtube:sync": "node scripts/sync-youtube.mjs",
"build": "npm run youtube:sync && next build"
}
}A lite player that loads nothing until playLink to this section
A standard YouTube iframe loads a lot of JavaScript and sets cookies the moment the page opens. A lite player shows the thumbnail and only swaps in the iframe when someone presses play:
"use client";
import { useState } from "react";
export function LitePlayer({ id, title }: { id: string; title: string }) {
const [on, setOn] = useState(false);
return (
<div style={{ position: "relative", aspectRatio: "16 / 9" }}>
{on ? (
<iframe
src={`https://www.youtube-nocookie.com/embed/${id}?autoplay=1&rel=0`}
title={title}
allow="autoplay; encrypted-media; picture-in-picture"
allowFullScreen
style={{ position: "absolute", inset: 0, width: "100%", height: "100%", border: 0 }}
/>
) : (
<button type="button" onClick={() => setOn(true)} aria-label={`Play video: ${title}`}>
<img src={`https://i.ytimg.com/vi/${id}/hqdefault.jpg`} alt="" loading="lazy" />
</button>
)}
</div>
);
}The youtube-nocookie.com domain is YouTube's privacy-enhanced mode. If your site sends a Content-Security-Policy, allow i.ytimg.com in img-src and www.youtube-nocookie.com in frame-src. You can try the component in the code playground.
For Shorts, the vertical thumbnail lives at https://i.ytimg.com/vi/ID/oar2.jpg. On my site, a full-height Shorts feed uses CSS scroll snapping (scroll-snap-type: y mandatory) and only mounts an iframe for the Short in view, so swiping through sixteen Shorts never loads sixteen players.
VideoObject structured dataLink to this section
Describe each video in JSON-LD so search engines understand the page:
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "The WordPress Update That Let Hackers In",
"description": "How a race condition in the WordPress core updater was exploited, and how to update safely.",
"thumbnailUrl": "https://i.ytimg.com/vi/VIDEO_ID/hqdefault.jpg",
"uploadDate": "2026-11-10T09:00:00+05:30",
"embedUrl": "https://www.youtube.com/embed/VIDEO_ID",
"contentUrl": "https://www.youtube.com/watch?v=VIDEO_ID"
}uploadDate comes straight from the feed's published field. For a list page, wrap several of these in an ItemList. The schema generator and the JSON-LD guide cover validation.
The daily loop, end to endLink to this section
| When | Who | What |
|---|---|---|
| Morning, 10 minutes | Claude, then you | /daily-video, then approve the topic and check sources.md |
| Day 1 | You | Record or render the Short; post it at your usual time |
| Day 2 | You | Post the long video; set it as the Short's related video |
| Next deploy | Build script | youtube:sync pulls both into the site; pages update themselves |
| Weekly | You | Look at views and click-through, then adjust the pillars in the skill |
The skill keeps the process consistent; the sync keeps the website current; you keep the judgement. That split is what makes a daily habit realistic alongside client work.
Frequently asked questionsLink to this section
Do I need Claude Code specifically?Link to this section
The ideas work with any assistant that can search, read pages and write files. A Claude Code skill is convenient because the instructions live in your repository next to the scripts they call, and you run them with one command.
Is it OK to publish AI-assisted videos?Link to this section
Yes, as long as the facts are yours to vouch for and you follow the platform's rules. YouTube asks creators to disclose realistic altered or synthetic content, such as AI-generated realistic people. Check the current policy and tick the disclosure when it applies.
How do I get my channel ID?Link to this section
Open your channel page, view the page source and search for "externalId", or find it in YouTube Studio under Settings β Channel β Advanced settings. It starts with UC.
Test yourself
3 quick questions on this lesson.
Finished this lesson?
Mark it complete to track your progress through the learning paths.