---
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.
