Jose Romero

The workflow behind the videos

Companion to the video "How Claude Code makes my YouTube videos". Ten stages, one folder per video, and the Claude Code skill files that run them, as they were on September 4, 2026.

This is a snapshot, not a maintained page. The workflow keeps changing; later videos will carry their own version. The skill files are generic copies: personal rules, private paths and names removed. Drop one into .claude/skills/<name>/SKILL.md in your own repo, type its slash command, and adapt the paths.

Ten stages

#StageOwnerSkillGate
1IdeaAI + human/capture, /ideassimilar videos show a live audience
2ResearchAI/researchevery number spoken exists in research.md with a source
3Packaging firstAI + human/new-video20 titles, 3 picks paired to 3 thumbnails, locked before the outline
4Beat mapAI/new-videoloops open and close, hook verbatim, at most 5 beats
5SlidesAI/slidesslide IDs match the beat map, every slide screenshot-audited
6RecordHuman/recordpre-flight rig + privacy list, one take, clap on a flub
7EditAIpostprod commandsilence cut, captions with a name dictionary, loudness pass
8Copy + checkAI/post-production, /video-checkall copy from what was said, 8-point report card
9PublishHumanmanual, then /blogunlisted, Substack first, then public, then the site
10RetroAI + human/retropromise check, one repeat, one change, skill edits proposed

One folder per video holds every artifact: brief, research, titles, beat map, deck, raw recording, cuts, captions, description, article, review. Every stage writes files, never chat, so a fresh AI session can pick up any stage cold. The AI drafts everything and decides nothing public.

The skill files

A skill is a markdown file Claude Code loads when you type its slash command. Ten from the repo, scrubbed. Each says what it reads, what it writes, and the gates it enforces.

/capture

Stage 1, idea intake

Ultra-light idea intake, built for mobile/Remote-Control. Append a raw idea to content/ideas.md instantly (lossless), then tidy it, pillar, number, dedupe, privacy/format flags. NEVER scaffolds folders. Trigger, the creator says "capture", "idea:", or drops a raw idea line (esp. from phone).

/capture <raw idea>raw .md35 lines
Show the file
---
name: capture
description: Ultra-light idea intake, built for mobile/Remote-Control. Append a raw idea to content/ideas.md instantly (lossless), then tidy it, pillar, number, dedupe, privacy/format flags. NEVER scaffolds folders. Trigger, the creator says "capture", "idea:", or drops a raw idea line (esp. from phone).
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/capture/SKILL.md and invoke with /capture <raw idea>. -->

# Capture, mobile idea intake

The phone-first front door to the idea bucket. The creator fires a half-formed idea from anywhere; this lands it safely and sharpens it. Optimized for a small screen and a moving target, **short replies, no essays.**

This is intake only. It is NOT `/ideas` (the daily pick + topic validation + research) and NOT `/new-video` (folder scaffold after a pick). Capture never researches and never scaffolds, it hands off to those.

## Rules

1. **Append-first, lossless, do this before anything else.** The moment the creator sends an idea, write it into `content/ideas.md` as the next number, keeping **their exact wording** (a tidied phrasing can follow in parens, but never overwrite his words). Losing a phone-thrown idea is the one unforgivable failure here.
2. **Place it:** pick the right pillar (1 De-Google/self-host · 2 Linux · 3 AI workflows · 4 Build-in-public · 5 Story/lifestyle/money), or add to the current dated capture batch if it's a grab-bag. Give it the next sequential number.
3. **Then improve it** (this is the "ideas we can improve" part, fast, one pass):
  - **Dedupe:** scan the existing bucket (#1, N). If it overlaps an existing idea, say "related to #M" and either merge or note the distinct angle, don't create a near-duplicate.
  - **Sharpen:** offer a tighter, title-shaped version, but keep the original wording in parens.
  - **Flag** inline, only if relevant:
   - 🔒 **Privacy**: employer, location, family, grey-area side projects. Flag, don't drop.
   - 🔎 **Home vs search** hint (search = shorter/faster/simpler/more-complete intent).
   - 📐 **Format**, list / story / news (timely) / tutorial / stairstep.
   - ⭐ **Strong near-term candidate** if it's got obvious wow + is easy to ship now.
4. **Never scaffold a folder.** That's `/new-video`, and only after the creator explicitly picks. Capture stops at the bucket line.
5. **Batch:** if the creator sends several at once, add them all, then give one compact summary.
6. **Reply compact** (they are on a phone): confirm with `#N · Pillar X · <one-line>` and any flag. Do NOT paste the whole file back. One or two lines is the target.

## "Tidy the bucket" mode
If the creator says "tidy the ideas" / "clean the bucket": do a full-file pass, dedupe across all pillars, regroup any strays, collapse merges, and surface 2-3 stale-but-strong ideas that have been sitting. Report only the *changes* (moved/merged/flagged), not the whole list.

## Remote / on-the-go note
This skill is the durable home of the intake rules, so it works the same in any session, a fresh one, or a named remote session (`claude --remote-control "ideas"`) reconnected from the phone. Behavior lives here, not in the conversation, so a `/compress` or a new session never changes how capture behaves. Nothing leaves the machine (Remote Control keeps files local; see the mobile note in `content/ideas.md`).

/ideas

Stage 1, backlog + validation

Refill and rank the video idea backlog, mine logs/frustrations, validate topic demand, keep the pillar mix healthy. Use for "new ideas", "refill the backlog", or the Sunday weekly review.

/ideasraw .md15 lines
Show the file
---
name: ideas
description: Refill and rank the video idea backlog, mine logs/frustrations, validate topic demand, keep the pillar mix healthy. Use for "new ideas", "refill the backlog", or the Sunday weekly review.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/ideas/SKILL.md and invoke with /ideas. -->

# Idea generation

1. Mine sources, newest first: `log/*.md` (frustrations/wins are ideas, the capture rule), recent video retros, `strategy/brand-audit-2026-07.md` transferable-tactics table, and anything the creator mentions.
2. **Validate before adding** (NetworkChuck rule): WebSearch/YouTube-search the topic, if comparable videos sit at ~200 views, the audience isn't there; note "weak demand" instead of adding. If a niche is underserved but adjacent demand is strong (e.g. only ~46 Claude Code tutorials tracked), flag it as a wedge.
3. Append one-liners to `content/ideas.md` under the right pillar, no formatting fuss. Mark used ideas `[NNN]`.
4. Check pillar mix for the coming week (rough weekly balance, energy beats sequencing).
5. Upgrade path (needs YouTube Data API key, not yet configured): competitor outlier scan + comment mining per the Kacper pipeline; until then this skill is manual-signal driven.

/research

Stage 2, research

Deep research for a video or channel question, web fan-out, source fetch, claims with citations, honesty guardrails. Use when the creator says "research X" or a video brief needs its research.md filled.

/research <topic>raw .md22 lines
Show the file
---
name: research
description: Deep research for a video or channel question, web fan-out, source fetch, claims with citations, honesty guardrails. Use when the creator says "research X" or a video brief needs its research.md filled.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/research/SKILL.md and invoke with /research <topic>. -->

# Video research

1. Scope: restate the question; decompose into 3-5 angles (what/how/counter-evidence/pricing/audience-language).
2. Run legs in parallel where available:
  - **WebSearch fan-out** (always available): one search per angle; fetch the 3-5 strongest sources; extract claims WITH quotes and URLs.
  - **`/last30days`** (if its sources are configured, run its doctor check): fresh social sentiment/what people actually say.
  - **NotebookLM** (after the creator has run `notebooklm login` once, see `pipeline/tools.md`): build a notebook from the top sources, query the 5 breakdown aspects; free Google infra, saves Claude tokens.
3. Cross-check: where legs disagree, say so explicitly, disagreement is signal.
4. Write to the video folder's `research.md` (or `strategy/` for channel-level questions):
  - Claims grouped by video beat, each with source link; confidence labels ([V]erified / [E]xtracted / [D]irectional) like `strategy/brand-audit-2026-07.md`.
  - **Honesty guardrails** section: what NOT to oversell + per-video privacy no-gos.
  - Numbers destined for the script get their own table, every number said on camera must exist here.
5. For heavyweight channel-strategy research, use the deep-research workflow instead (adversarial verification); for daily video prep this skill alone is enough.
6. **Readwise source hygiene (tag convention).** Any source saved to Readwise Reader for this video gets tagged **`video-NNN`** (plus a short topic tag, e.g. `border-phone-search`). That tag is the anchor `/blog` uses to auto-archive these sources out of the Reader inbox once the video publishes, so the inbox only ever holds what the creator is actually reading. Tag at save time; don't leave video sources untagged.

/new-video

Stages 3-4, packaging + beat map

Scaffold the next video project, pick/confirm an idea from content/ideas.md, create content/videos/NNN-slug/ with brief, recording guide, titles, description draft, and thumbnail drafts. Use when the creator says "new video", "next video", or names an idea to produce.

/new-videoraw .md25 lines
Show the file
---
name: new-video
description: Scaffold the next video project, pick/confirm an idea from content/ideas.md, create content/videos/NNN-slug/ with brief, recording guide, titles, description draft, and thumbnail drafts. Use when the creator says "new video", "next video", or names an idea to produce.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/new-video/SKILL.md and invoke with /new-video. -->

# New video scaffold

1. Determine NNN: next number after the highest in `content/videos/`. Slug: short-kebab from the working title.
2. If the creator didn't name an idea: show the 3 most relevant unused ideas from `content/ideas.md` and let them pick. Mark the chosen idea `[NNN]` in ideas.md.
3. **Packaging FIRST** (audit-backed rule, NetworkChuck/Geerling): draft `titles.md` (20 candidates + **3 picks: A/B/C, one per thumbnail**) and the thumbnail concept BEFORE locking the outline. If no title excites, the idea isn't ready, send it back to `/ideas`.
4. **Beat map before script**: write `beats.md` per `pipeline/script-craft.md`, loops opened/closed, mini-hooks, slide IDs. Script and slides both generate from it.
5. Create `content/videos/NNN-slug/` containing:
  - `brief.md`, from `content/templates/video-brief.md`, filled: verbatim hook, ≤5 outline bullets, ONE CTA, thumbnail concept. Voice per `brand/identity.md`.
  - `research.md`, facts/numbers/sources for every claim. Firsthand where possible; WebSearch only for external claims. Include an "honesty guardrails" section (what not to oversell + privacy no-gos for THIS video).
  - `recording-guide.md`, section-by-section talking points with 🎯 NAIL THIS markers; hook verbatim; per-section screen directions; the ⚠️ screen-privacy shot-list (copy pattern from 001).
  - `titles.md`, 20 candidates in a table (chars + formula per `content/templates/metadata.md`), then **3 picks (A/B/C) with reasoning, each paired to one of the 3 thumbnail drafts** (standing rule 2026-07-25: always 3 titles × 3 thumbnails, like 002/003's A/B test setup).
  - `description.md`, filled metadata template, timestamps as 0X:XX placeholders.
  - `talking-points.html`, the ON-SCREEN prep sheet the creator actually reads while recording. Template/style reference: a previous video's `talking-points.html` (dark `#1a1a1a`, orange headings, TAB chips, blockquoted source quotes, bridge lines, tab-order links at bottom, "never on the recorded screen" warning). Content mirrors cheatsheet/recording-guide, keep them in sync.
  - `thumbnail/`, 3 drafts at 1280×720 via ImageMagick: `#1A1A1A` bg, circular face cutout right third (from your face cutout), ≤4 words in `#F0A45E`/white (Liberation-Sans-Bold), signature-orange logo bottom-left. Reuse the magick recipe from 001's git history.
6. Then `/slides` generates the deck from the same `beats.md`; add a newsletter CTA line to the script (every video carries it, see brand audit).
7. Full draft transcript (`transcript.md`) only if the creator asks, the house rule is outline > script.
8. Hard rules: read your privacy rules file first; pressure-test the hook (would YOU keep watching?); ≤5 outline bullets/beats, no exceptions.

/slides

Stage 5, slides

Generate the video's slide deck (HTML + Mermaid, offline, brand-styled) from its beat map. Use after beats.md exists, or when the creator asks for slides/diagrams for a video.

/slidesraw .md23 lines
Show the file
---
name: slides
description: Generate the video's slide deck (HTML + Mermaid, offline, brand-styled) from its beat map. Use after beats.md exists, or when the creator asks for slides/diagrams for a video.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/slides/SKILL.md and invoke with /slides. -->

# Slide deck generation

House standard: `pipeline/slides/README.md`. Template: `pipeline/slides/template.html`. Reference deck: a previous video's `slides/deck.html`.

1. Read the video's `beats.md`, the Slide ID column defines exactly which slides exist. No orphan slides, no uncovered beats (`face` = camera only, no slide).
2. Copy the previous video's deck as the starting point (style continuity; decks are versioned so diffs show drift). Replace `<section id="...">` contents per beat.
3. Rules: one idea per slide; ≤5 text lines; numbers BIG (`.big`); diagrams > bullets (Mermaid `flowchart`, dark theme is preconfigured); brand palette only.
4. Write the source as `slides/deck-src.html`, then BUILD the presentable deck:
  `tools/.venv/bin/python tools/build_deck.py <video>/slides/deck-src.html` → `deck.html` (static, charts as inline SVG, signature embedded, publish-safe). Never present deck-src directly, mermaid renders hidden slides at zero size AND can throw live "Syntax error" bombs the built deck doesn't have (happened on 004). **Always include the red warning banner div at the top of deck-src's `<body>`** (`⚠️ SOURCE FILE, do not present. Open deck.html`), build_deck.py strips it from the built output. When handing off, give the creator the full path to `deck.html`, never just "the deck".
5. Footer on every slide: centered `your-site.com` (`#site` div in the template pattern). **Mouse nav is REQUIRED on every deck** : the `.nav` ‹ › buttons at mid-height left/right edges, wired to `show(i±1)`, pattern is in `pipeline/slides/template.html`; never ship a deck without them.
  **Caption-safe area (learned on 001):** YouTube/VLC closed captions render in the bottom-center of the frame, the bottom ⅙ of the screen (bottom 180px at 1080p). NO essential content (bullets, numbers, diagram nodes, table rows, mini-hooks) in that band; only the footer branding lives there, and it's accepted that CC-on viewers will cover it. If a slide's content creeps into the band, shrink or raise it.
6. Publish-safety: decks are hosted on the blog after the video posts, no private info, paths, or red-line content (incl. catch-all secrecy) in slides OR html. Check your privacy rules file.
7. **MANDATORY full audit: screenshot EVERY slide of the BUILT deck and LOOK at them.**
  `tools/.venv/bin/python tools/audit_deck.py <deck.html> <scratch-dir>` (1920×1080, waits out the entrance animations, plain firefox --screenshot fires at t=0 and captures empty slides), then montage and inspect. Check: text overflow/cramped chart nodes, chart+label readability at distance, footer/signature not overlapped, animations settle to fully-visible content, **and nothing but the footer inside the bottom-⅙ caption-safe band**. Fix and re-audit until clean, never hand off unseen slides.
8. Add `[SLIDE: id]` cues to `recording-guide.md` if any beat changed.

/record

Stage 6, recording

Run the recording session for a video, one-shot full recording guide (hook + all sections in a single output the creator leaves on screen), with pre-flight rig and privacy checks first. Use when the creator says he's ready to record.

/recordraw .md16 lines
Show the file
---
name: record
description: Run the recording session for a video, one-shot full recording guide (hook + all sections in a single output the creator leaves on screen), with pre-flight rig and privacy checks first. Use when the creator says they're ready to record.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/record/SKILL.md and invoke with /record. -->

# Recording session runner

1. Identify the video folder (latest `content/videos/NNN-*/` with unchecked "Recorded" in brief.md, or ask).
2. **Pre-flight** (confirm each, don't skip): OBS correct scene; **audio: say one sentence, mixer must peak YELLOW (-15 to -10 dB), barely-green = Scarlett gain knob drifted again (it lost ~3 dB over weeks per the 2026-08 audit)**; **camera on wall power (or battery full) + recording light confirmed ON**, the camera has died mid-take twice (018 close bubble, 022 main cam at 13:05); DND on; run the ⚠️ screen-privacy shot-list from the video's `recording-guide.md` line by line.
3. **One-shot guide as an HTML page, NO mid-recording interaction.** the creator reads talking points from a styled HTML page in the browser, NOT from the terminal. Generate/refresh `talking-points.html` in the video folder and open it in Firefox. Template: a previous video's `talking-points.html`, dark bg `#1a1a1a`, orange `#F0A45E` headings, numbered TAB/section chips, 🎯 markers, bridge lines in italic teal, source quotes as orange-bordered blockquotes, ⚠️ warnings in amber, clickable tab-order list at the bottom, and the closing warning that the page must NEVER appear on the recorded screen (other monitor only). Also print a compact fallback guide in chat. Never use a "go"/"next" loop, they cannot type while rolling.
4. Include the flub rule once at the top of the guide: flub = pause 2 s, clap once, restart sentence, keep rolling. One take. Hook re-record LAST if it didn't land.
4b. **HOOK FIRST, greeting second.** The scripted hook is the literal first words on camera. Any "welcome back" or series line moves to AFTER the hook lands (hook → one-line intro → content). Roughly half of viewers decide in those seconds, and early videos kept burying the hook behind a preamble. Make the guide's top card show the hook VERBATIM as item 1 and the intro line as item 2, visually impossible to read in the wrong order. If the hook wasn't first on camera, re-record just the hook before ending the session.
5. After "done": check off "Recorded" in brief.md, note the raw filename, and point to `/post-production`.

/post-production

Stages 7-8, edit + copy

Turn a raw recording into publishable assets, silence-cut, captions, timestamps, final description, social posts. Use after recording, when the creator says "post" / "edit" / "post-production".

/post-productionraw .md34 lines
Show the file
---
name: post-production
description: Turn a raw recording into publishable assets, silence-cut, captions, timestamps, final description, social posts. Use after recording, when the creator says "post" / "edit" / "post-production".
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/post-production/SKILL.md and invoke with /post-production. -->

# Post-production

Work inside the video's folder. Commands from `pipeline/daily-sop.md` block 3:

0. **Audio mastering is OPT-IN ONLY, do NOT run it by default.** the creator's ear test (2026-08-14) rejected the processed sound; the native OBS chain is the approved sound. `pipeline/bin/audio-master` exists for future experiments (audit + findings in `setup/audio-fix-2026-08/`), only when the creator explicitly asks.
1. `auto-editor recording.mkv --margin 0.3sec -b:a 256k -o edit.mp4` (adjust input name; `-b:a 256k` always, the 128k default downgraded every final until 025, this fix stays).
2. Whisper captions → `edit.srt` (see `pipeline/tools.md` for the installed variant).
  - **Name/term spelling pass is automatic:** `tools/whisper_srt.py` runs `tools/srt_fix.py` on every segment (dictionary `tools/srt_fixes.json`: Qwen, Unsloth, llama.cpp, MTP, DeepSeek, Strix Halo, ROCm, FastAPI, CachyOS, GMKtec…). For an.srt made any other way, run `python3 tools/srt_fix.py final.srt` (keeps `.asr-orig`, prints every changed line). When a review finds a new mis-hearing, ADD it to the JSON so it never recurs. Judgment fixes (garbled phrases like "token's best line" → "tokens baseline") stay manual: correct them with confidence, list them for the creator.
3. From the.srt: real chapter timestamps → replace 0X:XX in `description.md`. Chapters = the section boundaries, phrased as curiosity, not labels.
4. All copy from what was actually SAID (parse the.srt), never invent claims that aren't in the video:
  - Final YouTube description (update `description.md`)
  - `posts.md`, 3 X/Twitter variations for **Buffer** (X + IG scheduler; see `content/social/README.md`). Use a `<PRIMARY LINK>` placeholder for the CTA, funnel priority is Substack post URL (email capture) > YouTube (reach) > website. LinkedIn dropped 2026-07-27. Voice: `brand/identity.md`; zero corporate speak.
  - Pin-comment draft (the CTA question)
5. Verify against the ⚠️ shot-list that nothing private is visible in `edit.mp4`, spot-check frames at each screen-share chapter (ffmpeg frame grabs).
6. **Thumbnail refresh from the actual footage** (so every video's thumb shows current look, hoodie, haircut, expression that's really in the video):
  a. Grab webcam-box crops densely in the hook + CTA windows (that's where the creator looks at the lens): `ffmpeg -ss T -i final.mp4 -frames:v 1 -vf "crop=W:H:X:Y"...` every 2-3 s, montage, pick a calm/confident eye-contact frame (rule 4 in `brand/thumbnails.md`, no mid-blink, no mid-word mouth).
  b. Cutout: `rembg` python API with the `u2net_human_seg` session (person-only; model cached in `tools/.cache/u2net`), then `magick -brightness-contrast 10x8`, webcam stills run dim. Save as `thumbnail/still-<t>-cutout.png`.
  b2. ⚠️ **Portrait-crop the cutout (rule added 2026-07-27 after the creator rejected 007 v1):** full-frame webcam cutouts keep the chair/mic and leave the face small and low, it ends up UNDER the text. Crop to a portrait window around the subject first (`magick still-X-cutout.png -crop 1500x1860+1020+300 +repage -trim +repage`, adjust window to the framing), then build. Gate before showing the creator: face large, anchored right, head fully inside frame, and **zero text-over-face overlap** at full size.
  c. Point the video's `thumbnail/spec-*.json` cutouts at the new still, rebuild via `tools/build_thumb.py`, and gate with the 168px shrink test. Thumbnail text/badges must only promise what the video actually says (rule 10, cash every promise; verify against the transcript).
6b. **A/V sync correction (calibrated 2026-07-28; STANDARD STEP).** The home-rig webcam/capture pipeline delays VIDEO relative to audio by a measured **~0.26 s** (you hear speech/clap ~0.26 s before the mouth/hands move). Confirmed with an in-frame clap test: two claps gave +250 ms and +267 ms (mean ~258 ms). **Apply this to every home-rig recording** as part of postprod.
  - **Apply (fast, no re-encode):** `ffmpeg -i final.mp4 -itsoffset 0.26 -i final.mp4 -map 0:v -map 1:a -c copy -shortest final-synced.mp4` (delays audio to meet the late video), then shift `final.srt` by **+0.26 s**. Back up the pre-sync file as `final-presync.mp4`.
  - **Verify/re-measure per recording when the clap is in frame** : audio clap = argmax|samples| near the clap; visual clap = the 60fps frame where hands meet; offset = visual - audio. If it differs from 0.26 s by >1 frame (~17 ms), use the measured value. This keeps it honest without assuming the constant is eternal.
  - ⚠️ **Non-home recordings (phone, travel, other rig): the 0.26 s does NOT apply, the creator will flag these.** Re-measure from that video's in-frame clap, or if there's no delay in that pipeline, skip the correction. Never blindly apply 0.26 s to a non-home-rig file.
  - v9 note: corrected with 0.29 s (measured before the in-frame test), within tolerance of the true 0.26 s, looked great, shipped as-is.
7. Check off Edited/Captions in brief.md. Remind: thumbnail pick 15-min cap, then Block 5 publish steps are MANUAL (human approves everything public). Note:.srt is a sidecar, captions are never burned in; players (VLC/mpv) auto-load a same-named.srt, YouTube shows it only when the viewer turns CC on.
8. **Run `/video-check`**, grade this video against "the basics" and write `review.md` + append the trend row to `content/videos/REVIEW-LOG.md`. Surface any 🔧 fix-now items (cheap, pre-publish) and the ⏭️ next-time list. Never blocks the publish (ship daily > perfection); it's how the videos improve week over week.

/video-check

Stage 8, report card

Grade a recorded video against "the basics" and write a report card so videos improve week over week. Run during edit (after captions exist, before publish). Trigger, the creator says "check the video" / "run the checklist" / "video-check", or post-production reaches its final step.

/video-checkraw .md75 lines
Show the file
---
name: video-check
description: Grade a recorded video against "the basics" and write a report card so videos improve week over week. Run during edit (after captions exist, before publish). Trigger, the creator says "check the video" / "run the checklist" / "video-check", or post-production reaches its final step.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/video-check/SKILL.md and invoke with /video-check. -->

# Video check, the basics scorecard

A **learnable-skills report card**, run at edit time. It does NOT relitigate the idea or chase algorithm/game-level strategy, the gate from the framework is: **under ~2,000 views/video, you stay in the basics.** That's us. So this grades execution of the basics only, and its main output is **what to fix next time.**

Source of the criteria: a small-channel basics framework (under ~2,000 views per video you are still in the basics). The checklist below is the distilled contract.

Non-negotiable framing: **ship daily > perfection.** This report never blocks a publish. It sorts findings into **fix-now** (cheap, no re-record, title length, thumbnail element count) vs **next-time** (needs a re-record or a habit change). Bias every recommendation toward the next video, not toward delaying this one.

## Inputs (read from `content/videos/NNN-slug/`)
- The transcript: `final.srt` (preferred) or `recording-edit.txt`, this is the ground truth for what was said and the timing.
- `brief.md`, the intended hook (verbatim), the ONE CTA, thumbnail concept, and whether the creator pre-declared **home vs search**.
- `titles.md` / `description.md`, the chosen title + chapters.
- `thumbnail/`, the 3 drafts.
- The video file (`final.mp4`) only if a timing/pacing question needs a frame grab; otherwise the.srt timestamps are enough.

If the creator hasn't declared home vs search for this video, infer it and say which you assumed, it changes half the checks.

## The scorecard, grade each ✅ / ⚠️ / ❌ with a one-line why

1. **Intro (first ~30 s), heaviest weight.** ~50% of viewers leave here.
  - Formula present? **concept → stakes ("because…" / "can I pull it off?") → optional ending preview.** One sentence can carry all three.
  - Starts *immediately*, no "hey guys, welcome back," no throat-clearing, no long channel preamble.
  - From the.srt: read the first ~30 s verbatim into the report and mark exactly where the actual content starts.

2. **Title** :
  - **< 50 characters** (YouTube truncates). Count and show the number.
  - **Specific over mysterious** ("My tractor broke, now it costs $500" beats "You won't believe…"). Curiosity-gap only earns its keep with an audience that already trusts us, we don't have that yet.
  - **Complements, never duplicates, the thumbnail**, title text and thumbnail text must not say the same words.
  - **Delivers**, every promise/claim in the title is actually paid off in the transcript (no undelivered clickbait).

3. **Thumbnail** (against `brand/thumbnails.md` + the framework):
  - **≤ 3 elements.** Fills tthey canvas (most views are phone-sized). Text is read *before* the title → it must not repeat the title.
  - **3 variants armed for YouTube's built-in A/B test** (our standing 3×3 rule), even with no statistical winner, A/B teaches 3× faster.

4. **Storytelling**, is there a spine or an info-dump?
  - Story = **intention + obstacle**; telling = narrating the collision. Look for a chain: problem #1 → what happened → "next…" → problem #2. Note if it's a flat list with no tension.

5. **Homepage vs search**, never merge the two intents.
  - **Search video** wins on 4 axes: **shorter · starts solving faster (no preamble) · easier to understand (≈3rd-grade language) · more complete than what currently ranks.** Grade against those four.
  - **Homepage video**: frictionless, **every jargon term explained in ≤5 s** with a plain analogy, **speed front-loaded** (if the video shows 10 things, ~5 in the first minute), **scene changes in the first 3 min** (different shots/screens, not the same frame cut fast).

6. **Jargon sweep**, scan the transcript for technical terms (systemd, Docker, LLM, MCP, quantization, DNS, etc.). List any used **without a ≤5-second plain-language analogy.** These are the exact lines that lose non-converted viewers.

7. **What to remove next time**, the biggest beginner problem is **repetition**, then dullness.
  - **Said-then-showed:** if the narration says "let me Google this" and the screen then shows the Googling, one of them is dead weight, flag it.
  - **Impact ∝ screen time:** low-impact moments getting long screen time = cut candidates. List the specific timestamps.
  - Keep struggle that moves the story; cut filler.

8. **Speak / audio** (from the transcript, footage only if needed): note obvious rushing (run-on delivery, no breaths), mumbled/unclear stretches, or dead air the edit missed. Mic distance/quality is a record-time fix, note it for `/record`, don't re-grade it every time.

## Output

1. **`content/videos/NNN-slug/review.md`**, the report card:
  - Header: video NNN, title (+char count), declared/assumed **home-or-search**, and whether it serves that intent.
  - The 8 items, each ✅/⚠️/❌ + one line.
  - **🔧 Fix now (cheap, before publish):** bullet list, or "none."
  - **⏭️ Next time (habit / re-record):** the top 3 highest-leverage changes, most impactful first.
  - **✅ Keep doing:** one thing that clearly worked (so we reinforce, not just correct).

2. **Append one row to `content/videos/REVIEW-LOG.md`** (create with the header if missing) so the trend is visible, this is how we answer "are the videos improving?":
  `| date | NNN | home/search | intro ✅? | title chars | top next-time fix |`
  Before writing the row, glance at the last 3-5 rows: if the **same next-time fix keeps recurring**, say so explicitly in `review.md` ("this is the 3rd video flagged for a slow intro") and, if it's a process gap, propose a one-line rule for the relevant skill (`/record`, `/post-production`, `/new-video`), that's how the checklist makes the videos actually improve, not just get graded.

## Relationship to other skills
- Runs **inside/after `/post-production`** (post-production produces the assets; video-check grades them). Post-production's final step should invoke this.
- **Not** `/retro`, retro is a 48-h-later post-mortem about the whole launch (packaging, metrics, publish friction) and proposes skill edits. video-check is same-day, execution-only, basics-only.
- Keep it fast, this is a gate, not an essay. A report the creator can read in 60 seconds beats a thorough one he skips.

/blog

Stage 9, site article + Substack

Turn a published video into a full blog article on your-site.com, detailed write-up with embedded video, findings, and sources. Use when the creator gives a YouTube URL after upload, says "blog NNN", or asks for the website post for a video.

/blog NNNraw .md41 lines
Show the file
---
name: blog
description: Turn a published video into a full blog article on your-site.com, detailed write-up with embedded video, findings, and sources. Use when the creator gives a YouTube URL after upload, says "blog NNN", or asks for the website post for a video.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/blog/SKILL.md and invoke with /blog NNN. -->

# Video → blog article

Every published video gets a full article on the site, the website compounds alongside the channel. Trigger: the creator provides the video's YouTube URL (final step of the publish flow) or names a video.

1. **Gather** from `content/videos/NNN-slug/`: `research.md` (claims + sources), the final transcript (`recording-edit.txt` / `final.srt`), `description.md` (chapters + links), `brief.md`. The article is built from what was actually SAID plus the verified research, same honesty rules as descriptions (no claims the video doesn't make; keep "alleged", nuance lines, and honesty guardrails intact).
2. **Write** `site/app/letters/(posts)/<slug>/page.mdx` (the section is called **Letters**, route `/letters`):
  - `export const metadata = { title, description }` at top.
  - H1 title, then the **embedded video** right under the intro paragraph:
   `<iframe className="aspect-video w-full rounded-lg border border-teal" src="https://www.youtube.com/embed/<VIDEO_ID>" title="<title>" allowFullScreen />`
  - Structure: hook/intro (2-3 paragraphs, first person, `brand/identity.md` voice) → the findings/story in sections (## headings) → an honest-limits or takeaways section → **Sources** section listing every article/repo/tool with links → end on the Sources section (the post layout appends the subscribe form automatically; NO closing series footer line).
  - 600-1200 words. Written prose, not a transcript dump. Zero corporate speak.
  - ⚠️ **No markdown pipe tables in MDX** (no remark-gfm in the site config; they render as literal `|` text, bit us on 014). Use a plain HTML `<table>` with tailwind classes (pattern in `never-buy-a-new-car/page.mdx`), or restructure as per-item bold lines like the Substack version.
3. **Slides + diagrams** (whenever `content/videos/NNN-slug/slides/` exists, if we built them, they ship with the article):
  - Rebuild so the deck is current and fully self-contained (the builder inlines ALL images):
   `tools/.venv/bin/python tools/build_deck.py content/videos/NNN-slug/slides/deck-src.html`
  - Host the deck: `cp.../slides/deck.html site/public/decks/<post-slug>.html`
  - Export the mermaid charts as 2× PNGs (named by slide ID):
   `tools/.venv/bin/python tools/extract_diagrams.py.../slides/deck.html site/public/diagrams/<post-slug>`
  - In the MDX: `import { Diagram, SlideDeck } from "@/app/components/post-media";`
   - `<Diagram src="/diagrams/<post-slug>/<id>.png" alt="…" caption="…" />` for each chart, placed where the prose covers that idea (the slide's muted line usually makes a good caption). Charts with no matching prose stay deck-only, don't force them.
   - `<SlideDeck href="/decks/<post-slug>.html" title="<video title>" slides={N} />` right after the Sources section.
  - Privacy gate applies to the DECK too, it's now public site content: reread every slide + embedded screenshot against your privacy rules file before staging.
4. **Register** in `site/lib/site.ts`: ONE entry in `posts` (slug/title/date/description/`videoUrl`/`substackUrl`), newest first. `date` = the day the video was RECORDED, not published. The `videoUrl` renders the ▶ YouTube icon in the unified Writing list (`app/components/post-list.tsx`). **`substackUrl`** = the published Substack article URL; setting it auto-renders the "Read this on Substack" banner above that letter's title (via `SubstackBanner`). In the Substack-first publish flow, the Substack post is live before the site push, so fill this in. Note: Substack is the single subscribe source of truth, the site has no email capture; do not add one.
5. **Verify**: `cd site && npm run build` must pass. Check the new route appears.
6. **Update ledgers**: `content/videos/INDEX.md` (blog column/link), daily log.
7. **Substack version** (standing step, 2026-07-27): after the site article is final, write `substack.md` into the video folder, paste-ready for the Substack editor (your Substack). Format: line 1 = Title, line 2 = Subtitle, blank line, then body. **The Substack subtitle is a SHORT punchy one-liner (~8-12 words) that complements the title, NOT the long SEO metadata.description** (that's fine for the site `<meta>`, but it's way too long as a Substack subhead, the creator flagged this on 011). Write a fresh tight subtitle. Conversion rules: bare `https://www.youtube.com/watch?v=ID` URL on its own line (auto-embeds, never the /embed/ iframe); site-relative links → absolute `https://your-site.com/...`; Diagram components → the absolute PNG URL on its own line + the caption as an italic line under it; SlideDeck → a "[View the slide deck →](absolute URL)" link; NO series or "originally published" footer line, the body ends on the Sources list. Then render the copy-paste page: `tools/.venv/bin/python tools/substack_html.py <video-folder>/substack.md` → `substack.html` (Substack pastes rich text, NOT markdown, raw.md paste shows literal ## and [](); discovered 2026-07-28). Open the.html in Firefox for the creator: copy Title/Subtitle fields, click Select+copy body, paste, press Enter after each bare URL line to trigger embeds. Publish manual.
8. **Publish is MANUAL**: never `git push` / deploy without the creator's explicit go, show him the draft (dev server or the MDX) and wait for approval. Vercel deploys on push.
9. Privacy gate before commit: run the article against your privacy rules file (no employer, no location, no family beyond allowed, no personal red-line content).
10. **Archive the video's Readwise sources, inbox hygiene (standing rule 2026-07-30).** Blog runs off a live YouTube URL, so the video is published → its research sources are done and should leave the Reader inbox. Steps:
  - `reader_list_documents(location='new', tag=['video-NNN'])` to get this video's tagged sources.
  - Catch stragglers: any source cited in `research.md`/`description.md` that's in the inbox untagged → tag it `video-NNN` + topic tag first (so the archive is auditable and the convention holds), per `/research` step 6.
  - `reader_move_documents(location='archive')` on all of them (≤50/call). Archive is **reversible, never delete.** Confirm the inbox is clean afterward.
  - Only touch this video's sources; leave everything else alone.

/retro

Stage 10, retro

48-hour post-publish retro for a video, performance vs the last 10, promise-delivery check, lessons into the wiki. Use when the creator says "retro NNN" or ~2 days after a publish.

/retro NNNraw .md19 lines
Show the file
---
name: retro
description: 48-hour post-publish retro for a video, performance vs the last 10, promise-delivery check, lessons into the wiki. Use when the creator says "retro NNN" or ~2 days after a publish.
---
<!-- Adapted from the hijoseromero production repo (Claude Code skill). Generic version: personal rules, private paths and names removed.
   Assumes a repo laid out as content/videos/NNN-slug/, content/ideas.md, pipeline/, tools/ (auto-editor, faster-whisper, Playwright).
   Drop this file at.claude/skills/retro/SKILL.md and invoke with /retro NNN. -->

# 48-hour retro

1. Ask the creator for the numbers from YouTube Studio (views, impressions CTR, avg view duration, retention graph shape, subs gained), no API access yet; when a YouTube API key lands in the env, pull automatically instead.
2. Write `content/videos/NNN-slug/retro.md`:
  - Numbers table + comparison vs the running averages of the last 10 videos
  - **Promise check:** did the video deliver what title+thumbnail promised? (Re-read titles.md pick vs transcript.)
  - Which title/thumbnail ran, and would the B option have done better?
  - One thing to repeat, one thing to change (append these to `log/` daily note)
3. Update the channel tracker with date + headline number.
4. Trend note: after 5+ retros exist, compare pillars, flag what the audience is actually voting for. Once there is enough data: hunt the "wave" topic and propose feeding it.
5. **Improve the pipeline, not just the videos:** end every retro by proposing concrete edits to the skills/templates that caused what went wrong (or codify what went right), e.g. a hook rule to `pipeline/script-craft.md`, a checklist line to `/record`, a title formula to `content/templates/metadata.md`. Skills are git-versioned; show the diff, the creator approves, commit. Log the change in the daily note.

Not included: the third-party social-listening skill (last30days, MIT) the research stage can call, and the repo's own CLAUDE.md, which holds the private rules.

Tools underneath

Everything runs locally on a Linux box. Nothing here calls a hosted service except the model itself and the web searches during research.