From knowledge
Watch YouTube videos, extract transcripts, harvest links, research claims, and synthesize repo-applicability recommendations. Use when: 'youtube', '/youtube-digest', 'watch this YouTube video', 'transcript for YouTube', user shares a youtube.com or youtu.be URL for a single public video (not a course platform). Actions: watch <url> (full pipeline), watch (dequeue epic queue), watch <n> (queue row), queue <url> (batch enqueue), transcript <url> (captions only), resume <video-slug>. Not for auth-walled course platforms — use /knowledge:course-digest.
How this skill is triggered — by the user, by Claude, or both
Slash command
/knowledge:youtube-digest watch <url> | watch | watch <n> | queue <url> | queue list | transcript <url> | resume <video-slug>watch <url> | watch | watch <n> | queue <url> | queue list | transcript <url> | resume <video-slug>The summary Claude sees in its skill listing — used to decide when to auto-load this skill
youtube-extraction deps: !`node -e "const fs=require('fs'),path=require('path'),p=process.env.CLAUDE_PLUGIN_DATA;process.stdout.write(p&&fs.existsSync(path.join(p,'node_modules','@melodic','video-digestion'))?'installed':'MISSING - run setup-deps.mjs (see Prerequisites)')"`
context/companion-primary-sources.mdcontext/gotchas.mdcontext/quality-gates.mdcontext/synthesis-contract.mdcontext/watch-pipeline.mdcontext/watch-queue.mdcontext/workflow.mdevals/evals.jsonevals/fixtures/driver-video-goldens.jsonevals/fixtures/variation-matrix-backlog.jsonextraction/acquisition/acquire-retry-policy.jsextraction/acquisition/acquire-retry-policy.test.jsextraction/acquisition/acquire-staged.test.jsextraction/acquisition/acquire-throttle.jsextraction/acquisition/acquire-throttle.test.jsextraction/acquisition/acquire-with-retry.jsextraction/acquisition/acquire-yt-dlp-auth.jsextraction/acquisition/acquire-yt-dlp-auth.test.jsextraction/acquisition/acquire.jsextraction/acquisition/acquire.test.jsyoutube-extraction deps: !node -e "const fs=require('fs'),path=require('path'),p=process.env.CLAUDE_PLUGIN_DATA;process.stdout.write(p&&fs.existsSync(path.join(p,'node_modules','@melodic','video-digestion'))?'installed':'MISSING - run setup-deps.mjs (see Prerequisites)')"
yt-dlp: !yt-dlp --version 2>/dev/null | head -1 || echo "MISSING — install yt-dlp (see Prerequisites)"
ffmpeg: !ffmpeg -version 2>/dev/null | head -1 || echo "MISSING — install ffmpeg (watch action only)"
ImageMagick: !magick -version 2>/dev/null | head -1 || echo "MISSING — install ImageMagick 7 (watch action only)"
Absorb a single public YouTube video (transcript + visual frames), harvest reference links, fact-check claims through deeper external research, and produce a prioritized repo-applicability menu. Video download, bulk frames, contact sheets, and shallow git clones use the OS temp directory — durable artifacts live under .work/<watch-epic>/<video-slug>/ per the video-digest slice convention.
Where this skill says "deeper research," use whatever external-research capability your project provides — for example the discovery plugin's /discovery:research / /discovery:research-deep when installed. Treat those as the reference implementation, not a hard dependency.
Video content is a secondary source (on-screen and spoken claims are hypotheses, not verified facts). Treat them as hypotheses until promoted through deeper external research, and apply your project's own source-trust conventions. Repo conventions override video claims — surface convention conflicts explicitly; never silently adopt a video's shortcut over team rules.
Derive .work/<watch-epic>/<video-slug>/ from metadata title + video id:
-<video-id> for uniqueness (e.g. ai-coding-tips-7zZy1QTvokM)Implementation: ${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/transcript/derive-video-slug.js
This skill's .work/ root is formally carved out of the marketplace topic-docs convention (https://raw.githubusercontent.com/melodic-software/claude-code-plugins/main/docs/conventions/topic-docs/README.md): the work root resolves through the knowledge plugin's own library_dir seam, not the concern file's memory_dir; slug conformance is form-only (kebab-case [a-z0-9-], ≤ 40 chars, Windows-reserved base names take an -x suffix); and nested <epic>/<slug>/ sub-slices are sanctioned. The root still self-ignores (a .gitignore containing *) and is never committed.
Every extraction command in this skill runs through run.mjs, and each writes its .work/<watch-epic>/… artifacts under a work root resolved by resolveWorkRoot(). That root honors the knowledge plugin's personal library_dir user-configuration seam, substituted into this skill's content as ${user_config.library_dir}:
Non-default — when ${user_config.library_dir} is a non-empty value other than the repo-root default . (and not an unexpanded ${user_config.library_dir} token), pass it as a leading --work-root flag on every run.mjs invocation in this skill:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" --work-root "${CLAUDE_PROJECT_DIR}/${user_config.library_dir}" <script.js> [args…]
run.mjs forwards it to the extraction child as YOUTUBE_WORK_ROOT (a double-quoted CLI arg is cross-platform; an inline YOUTUBE_WORK_ROOT=… node prefix is bash-only and fails under PowerShell). When library_dir is already absolute, pass it directly and drop the ${CLAUDE_PROJECT_DIR}/ prefix. This applies to all the run-script sites below — run-transcript.js, preflight-metadata.js, queue-claim.js, run-watch.js, watch-state.js, vision-gated-promote.js, init-watch-checklist.js, analyze-harvested-repos.js, check-research-complete.js, check-watch-outcomes.js, and run-resume.js — not only the first.
Default / unset — when ${user_config.library_dir} is ., empty, or still an unexpanded token, invoke run.mjs without --work-root. resolveWorkRoot() falls back to ${CLAUDE_PROJECT_DIR} (then process.cwd()), landing artifacts at the consuming repo root.
Agent-written artifacts share the same root — do not split the slice. Every .work/<watch-epic>/… path in this skill and its context/ files is relative to this same resolved work root, not always the repo root. That includes the paths you materialize by hand — the mkdir -p .work/<watch-epic>/claims and QUEUE.md copy/append steps under Queue action, the claims/*.json stubs, and every agent-authored slice artifact in the Output contract. When ${user_config.library_dir} is non-default, write them all under ${CLAUDE_PROJECT_DIR}/${user_config.library_dir}/.work/<watch-epic>/… so the queue table, its concurrency claims, and the --work-root script output share one root; a split root would let queue list / watch read claims from a different directory than the table being edited. Default / unset → repo-root .work/<watch-epic>/… as written.
The setup-deps.mjs install step is exempt — it installs node dependencies into ${CLAUDE_PLUGIN_DATA}, not the work root.
Four more personal userConfig options tune YouTube acquisition. Each is wired the same cross-platform way as --work-root — a leading, double-quoted flag on the run.mjs invocation that the launcher forwards to the extraction child as an environment variable (these env vars are internal plumbing, not a channel to set by hand). Apply the same guard as library_dir: pass a flag only when its option holds a non-empty value other than the option default, and not still an unexpanded ${user_config.…} token; otherwise omit it and the pipeline keeps its built-in default. All are leading and order-independent, so they combine with --work-root in any order:
| Option | Flag | Pass when | Effect |
|---|---|---|---|
${user_config.yt_dlp_js_runtimes} | --js-runtimes "<value>" | set and not the default node | off omits yt-dlp's --js-runtimes; any other value selects that runtime |
${user_config.yt_dlp_cookies_file} | --cookies-file "<value>" | non-empty | authenticated acquisition from a Netscape cookies.txt (never commit it) |
${user_config.yt_dlp_cookies_from_browser} | --cookies-from-browser "<value>" | non-empty | forces one browser's cookies instead of the automatic platform-ordered fallback; a cookies file wins over it |
${user_config.max_concurrent_acquires} | --max-concurrent-acquires "<value>" | set and not the default 1 | caps concurrent acquisitions (1–3); higher increases HTTP 429 risk |
Example combining a non-default library dir with a forced cookie source (unset options contribute no flag):
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" \
--work-root "${CLAUDE_PROJECT_DIR}/${user_config.library_dir}" \
--cookies-from-browser "${user_config.yt_dlp_cookies_from_browser}" \
<script.js> [args…]
| Action | Status | Behavior |
|---|---|---|
queue <url> [url...] | Active | Append URLs to epic .work/<watch-epic>/QUEUE.md; dedupe by video-id. |
queue list | Active | Show QUEUE.md table + active claims/*.json stubs. |
transcript <url> | Active | Captions only — no video download. Runs acquisition + transcript pipeline. |
watch | Active | Dequeue first pending queue row (FIFO) — claim stub → bootstrap → full skill pipeline. |
watch <n> | Active | Dequeue queue row #n only (parallel path across terminals). |
watch <url> | Active | Full pipeline: ≤1080p download → frame selection → vision absorption → link harvest → research agenda → repo-applicability synthesis. |
resume <video-slug> | Active | Continue interrupted watch from watch.json phase-map state in .work/<watch-epic>/<video-slug>/. |
Queue SSOT: context/watch-queue.md. Template: templates/queue.md.
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" transcript/run-transcript.js "<youtube-url>"
Pipeline:
--skip-download)[M:SS] paragraph transcript.txt.work/<watch-epic>/<video-slug>/transcript.txt + README.md stub (journey template: templates/readme-journey.md)Caption acquisition flags (see acquisition/build-yt-dlp-args.js): --write-subs --write-auto-subs --sub-langs "en.*,-live_chat" --sub-format vtt.
Epic queue at .work/<watch-epic>/QUEUE.md batches URLs before watch (canonical epic dir: youtube-watch). Claim stub first, table second — see context/watch-queue.md.
On first queue use:
mkdir -p .work/<watch-epic>/claimstemplates/queue.md → .work/<watch-epic>/QUEUE.md if missing# index (do not renumber existing rows)Dedupe on add: extractVideoId from ${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/acquisition/acquire.js — skip URLs whose video-id already appears in the table.
When the operator supplies companion URL(s) with queue intent, record before watch — SSOT: context/companion-primary-sources.md. Template: templates/companion-source-brief.md.
enqueue, derive video-slug from displayTitle + videoId..work/<watch-epic>/<video-slug>/source/companion-sources.md (section fan-out table + integration checklist).slug on the QUEUE.md row; notes → companion — source/companion-sources.md.Run before appending so a human or agent reading the queue sees what each row is without opening the URL, and dead links never enter the queue:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" acquisition/preflight-metadata.js "<url>" ["<url>"...]
Routes through the same spawnYtDlpWithAuthFallback path as acquisition (bot-checked videos are not falsely rejected). Per-URL JSON action/status decides enqueue-vs-reject and fills the title + channel columns — full decision table in context/watch-queue.md "Preflight (every queue add)".
queue listRead QUEUE.md and run:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/queue-claim.js list
Show which rows have active claim files.
watch or watch <n>)node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/queue-claim.js stale-check — reset abandoned in_progress rows to pending when claim files are older than 7 days.watch → first pending in # order; watch <n> → row #n must be pending or resumable in_progress you own.QUEUE.md):node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/queue-claim.js claim <n> [--video-id <id>]
Exit code 2 = row taken — for FIFO, try next pending; for watch <n>, stop with a clear message.
status → in_progress in QUEUE.md.run-resume.js when slice exists and phases remain).complete; on abort → failed + one-line notes.node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/queue-claim.js release <n>Parallel terminals: prefer watch 2 / watch 4 in separate sessions — not two auto-watch on the same row.
Phase-flow overview (mermaid diagram + phase summary table): context/workflow.md.
When source/companion-sources.md exists: run Phase 0b before run-watch.js. SSOT: context/companion-primary-sources.md.
WebFetch companion URL(s) → subagent fan-out per section table → source/companion-digest/<section-slug>.md + hub source/companion-digest/README.md → mark-phase <slice-dir> companion. No surface reads; use deep external research per section. Downstream phases frame against the digest (claim inventory, research agenda, vision, synthesis).
On resume: if companion unmarked, run 0b before vision even when CLI phases exist.
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/run-watch.js "<youtube-url>" [--skip-research]
Runs acquire (retry + throttle) → transcript → dynamic coverage watching → metadata link harvest. Writes:
.work/<watch-epic>/<video-slug>/source/transcript.txt.work/<watch-epic>/<video-slug>/run-state/watch.json — phase-map + tempSession paths.work/<watch-epic>/<video-slug>/key-frames/selection.json — temp frame/sheet paths (no bulk copy into repo).work/<watch-epic>/<video-slug>/key-frames/coverage-plan.json — dynamic sampling plan.work/<watch-epic>/<video-slug>/source/harvested-links.json.work/<watch-epic>/<video-slug>/run-state/continuation-prompt.mdBulk frames and contact sheets stay in tempSession dirs. Re-run run-watch.js when temp expired. highVolume: true in output → fan out vision subagents; no hard frame cap.
Before watch or resume when frames are needed:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/setup-deps.mjs"
STOP if pre-computed context shows MISSING for yt-dlp, ffmpeg, or ImageMagick — install them per the Prerequisites section below. Cloud agents without the media toolchain: fail closed — do not run watch.
After CLI bootstrap, parallelize like /knowledge:course-digest Phase 3:
| Wave | Agents | Output |
|---|---|---|
| Parallel | Transcript agent | Claims + timestamps → research/research-agenda.md draft |
| Parallel | Visual agent | Contact-sheet triage → detail reads → key-frames/visual-frames.md + on-screen URLs |
| Parallel | Link/repo agent | WebFetch previews + node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" harvesting/analyze-harvested-repos.js <slice-dir> when GitHub links exist |
| Sequential | Research fan-out | external research (standard or deep) per claim cluster → RESEARCH.md + research/findings/ |
| Sequential | Synthesis agent | recommendations/menu.md + recommendations/takeaways.md (hub: recommendations/README.md) |
| Sequential | Interview handoff | recommendations/interview.md → offer /interview for POC/full-slice picks |
Mark each phase in watch.json via node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/watch-state.js mark-phase <slice-dir> <phase> after the wave completes (idempotent — re-running an already-marked phase is a no-op). Promote only via vision-gated decisions:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/vision-gated-promote.js "<slice-dir>"
(promote-key-frames.js remains for ad-hoc single copies — not the completion path.)
After CLI bootstrap (or on resume), materialize and maintain the slice checklist:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/init-watch-checklist.js "<slice-dir>"
Use --force to regenerate per-sheet rows after contactSheetCount changes. Tick [ ] → [x] only with verification evidence (command exit code, artifact path, verify row). Binary criteria SSOT: context/quality-gates.md. Ordered checkboxes: templates/watch-checklist.md → slice run-state/watch-checklist.md.
Do not run mark-phase (watch-state.js mark-phase) or set status: complete while the phase verify script fails.
After CLI bootstrap (or on resume), execute these phases in the skill session (mirror checklist phases 2–9):
key-frames/vision-plan.md from deterministic signals + a small inspection sample:
run-state/watch.json (contactSheetCount, densificationWindows, highVolume, duration), key-frames/coverage-plan.json, key-frames/selection.json, transcript session boundariesconference-multi-session | single-talk | screencast | slide-talkcode-or-diagram, on-screen-text, relevant-to-synthesis; dedupe against transcript + prior research0b. Claim inventory (before research agenda) — write research/claim-inventory.md:
research/research-agenda.md clusters from the inventory; do not jump to research without this landscape pass0c. Staged deck harvest — template: templates/deck-inventory.md; contract: context/synthesis-contract.md
harvested-links.json (deck | repo | doc | other); fetch deck candidates from metadata/chapters → source/decks/<session-slug>/ + source/deck-inventory.mdskipsource/attachments/<kind>/; citations → research/sources.md (template: templates/sources.md)Vision absorption (three-pass) — contact-sheet triage → detail reads → transcript alignment → vision-gated promote + audit. Full per-pass procedure (JSON SSOT, scripts, promotion gates): context/watch-pipeline.md.
High-volume advisory — when frameSelection.highVolume is true, fan out vision subagents; do not truncate frames in temp.
Context-cost fan-out trigger (independent of highVolume) — Pass 2 accumulates a read-count: every keep-detail frame escalated to 1920×1080 is a full-res Read that will not be reused after the vision pass. When that count is high enough that the reads would flood main context — context-flooding output you won't reuse — route to a per-sheet vision subagent returning only JSON (triage rows), keeping the main watch context lean. The signal is deterministic (the skill surfaces the read-count, mirroring the highVolume boolean shape); the decide-to-delegate is the agent acting on that fact. Do not hard-force fan-out in a script — the agent may have context reasons to process inline; the skill documents the threshold, the agent routes.
Research stage (default-on) — gate: mark-phase <slice-dir> research only after check-research-complete.js exits 0 and agenda clusters are done or deferred:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" evals/check-research-complete.js "<slice-dir>"
research/claim-inventory.md must exist; draft or expand research/research-agenda.md with claim clusters mapped to inventory rowstemplates/research-cluster.md)RESEARCH.md + optional research/findings/*.mdresearch/findings/<cluster-topic-slug>.md (e.g. complex-types.md) — the topic, not an opaque RA1/RA2 ordinal; the agenda carries cluster orderinganalyze-harvested-repos.js clones to temp onlySynthesis (after research gate) — template: templates/synthesis-item.md
recommendations/ from templates/recommendations/ (hub README links all docs)recommendations/menu.md — categories: immediate-takeaway | worth-investigating | poc-candidate | full-slice | no-go; P0–P2 + consensus notesrecommendations/takeaways.md — safe actions without further researchrecommendations/questions.md — open questions for the userREADME.md per templates/readme-journey.md/interview → /planning:plan → /implementInterview handoff — write recommendations/interview.md with menu + "Should we go further?"; suggest /interview for POC/full-slice items.
Phase markers — after each skill phase, update run-state/watch.json via node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/watch-state.js mark-phase <slice-dir> <phase>.
Outcome verification (before status: complete) — mandatory host verify script:
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" evals/check-watch-outcomes.js "<slice-dir>" --write-report
Writes verification/<ISO-basic>Z-watch-outcomes.md. Do not mark the slice complete while this exits non-zero. Long conferences (conference-multi-session, ≥4h) must meet floors in context/quality-gates.md. Verify script triage-agentic-required fails selection-signals / missing model. Temp paths use {tmp} prefix (portable temp-session path serialization).
Queue completion: When this watch was started from QUEUE.md, set that row complete (or failed if verify never passes), run queue-claim.js release <n>, and refresh epic README breakdown.
Deterministic frame-selection stages (orchestrate-watching.js), the standalone pipeline command, and metadata-only link harvest: context/watch-pipeline.md.
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/run.mjs" watch/run-resume.js "<video-slug>"
Reads .work/<watch-epic>/<video-slug>/watch.json, identifies the next incomplete phase (acquire → transcript → watching → vision → harvest → research → synthesis), refreshes continuation-prompt.md, and emits a copy/paste-ready continuation prompt. When tempSession paths are missing, re-run run-watch.js before vision.
Handoff ritual (context pressure or session end):
watch.json phase markers with timestampscontinuation-prompt.md (completed phases, next phase, frame-selection state, known issues)/knowledge:youtube-digest resume <video-slug> to continue."Per video-digest slice. This is the single authoritative enumeration of every produced artifact — the contract a fresh watch is graded against. context/quality-gates.md phase/criterion tables point at this table for the lane + staged verdict; do not re-enumerate staging there.
KIND — SOURCE (acquired / harvested input), METADATA (script-emitted machine state), DELIVERABLE (agent-authored synthesis). Producer — script (a deterministic extraction/ writer materializes it, often from agent-authored JSON facts) or agent (authored inline by the watching/research/synthesis agent).
| Artifact | Lane | Staged | KIND | Producer |
|---|---|---|---|---|
README.md | root | yes | DELIVERABLE | agent (templates/readme-journey.md) |
RESEARCH.md | root | yes | DELIVERABLE | agent (external research synthesis; required before research phase done) |
source/transcript.txt | source | yes | SOURCE | script (write-transcript.js) |
source/harvested-links.json | source | yes | SOURCE | script (run-harvest.js; on-screen links merged by agent during vision) |
source/harvested-repo-analysis.json | source | yes (optional) | METADATA | script (analyze-harvested-repos.js; temp clone) |
source/deck-inventory.md | source | yes (optional) | SOURCE | agent (deck fetch log; decks under source/decks/) |
source/companion-sources.md | source | yes (optional) | SOURCE | agent (queue-time brief; templates/companion-source-brief.md) |
source/companion-digest/README.md | source | yes (optional) | DELIVERABLE | agent (hub linking section digests) |
source/companion-digest/<section-slug>.md | source | yes (optional) | DELIVERABLE | agent (per-section deep-dive; Phase 0b fan-out) |
research/claim-inventory.md | research | yes | DELIVERABLE | agent (claim landscape; sessions + boundaries) |
research/research-agenda.md | research | yes | DELIVERABLE | agent (claim clusters + status) |
research/findings/<topic>.md | research | yes (optional) | DELIVERABLE | agent (per-cluster shards, topic-named) |
research/sources.md | research | yes (optional) | DELIVERABLE | agent (templates/sources.md; decks/repos cited) |
key-frames/selection.json | key-frames | yes | METADATA | script (write-watching-manifest.js; temp paths + timestamps) |
key-frames/coverage-plan.json | key-frames | yes | METADATA | script (write-watching-manifest.js; dynamic sampling plan) |
key-frames/sheet-frame-index.json | key-frames | yes | METADATA | script (export-sheet-frame-index.js) |
key-frames/vision-plan.md | key-frames | yes | DELIVERABLE | agent (content class + segments + triage scope) |
key-frames/triage/batches/sheet_NNN.json | key-frames | yes | DELIVERABLE | agent (per-sheet vision verdicts; one subagent per sheet) |
key-frames/triage/manifest.json | key-frames | yes | METADATA | script (merge-triage-json.js over batches) |
key-frames/frame-triage-log.md | key-frames | yes | METADATA | script (render-triage-log.js from manifest) |
key-frames/visual-frames.md | key-frames | yes | METADATA | script (rebuild-visual-frames.js; pass-2 detail log) |
key-frames/visual-gaps.md | key-frames | yes (optional) | METADATA | script (expand-visual-gaps.js; densification windows without frames) |
key-frames/promotion-decisions.json | key-frames | yes | DELIVERABLE | agent (vision verdict per candidate PNG) |
key-frames/promotion-map.json | key-frames | yes | METADATA | script (vision-gated-promote.js; name map + traceability) |
key-frames/key-frames-manifest.md | key-frames | yes | METADATA | script (render-key-frames-manifest.js) |
key-frames/key-frame-quality-audit.json | key-frames | yes | DELIVERABLE | agent (post-promotion per-frame note, min 20 chars) |
key-frames/key-frame-quality-audit.md | key-frames | yes | METADATA | script (render-quality-audit.js from JSON) |
key-frames/frames/** | key-frames | yes | DELIVERABLE | script (vision-gated-promote.js; curated frames only) |
key-frames/contact-sheets/snapshot-meta.json | key-frames | yes | METADATA | script (snapshot-bootstrap.js; {tmp}-tokenized sourceDir) |
key-frames/contact-sheets/*.jpg | key-frames | never in git | METADATA | script (snapshot-bootstrap.js; local DR snapshot, gitignored) |
recommendations/README.md | recommendations | yes | DELIVERABLE | agent (hub — links menu, takeaways, questions, interview) |
recommendations/menu.md | recommendations | yes | DELIVERABLE | agent (prioritized repo-applicability menu) |
recommendations/takeaways.md | recommendations | yes | DELIVERABLE | agent (safe quick actions) |
recommendations/questions.md | recommendations | yes | DELIVERABLE | agent (open questions) |
recommendations/interview.md | recommendations | yes | DELIVERABLE | agent (end-of-watch /interview prompt) |
verification/<ISO-basic>Z-watch-outcomes.md | verification | yes | METADATA | script (check-watch-outcomes.js --write-report) |
run-state/watch.json | run-state | yes | METADATA | script (watch-state.js; phase-map + tempSession) |
run-state/watch-checklist.md | run-state | yes | METADATA | script (init-watch-checklist.js from template) |
run-state/continuation-prompt.md | run-state | yes | METADATA | script (watch-state.js; session handoff) |
media/frames/, media/contact-sheets/ | (OS temp) | never in repo | — | OS temp only |
*.vtt, video.* | (OS temp) | no | SOURCE | OS temp — regenerable |
Observed failure modes — recovery detail in context/gotchas.md: YouTube bot/sign-in cookie fallback, HTTP 429 backoff + concurrency cap, temp-session expiry (re-run run-watch.js before vision), cloud-agent media-toolchain fail-closed, retired watch-progress.json.
Verify before starting (stop and route to fix path on failure):
node "${CLAUDE_PLUGIN_ROOT}/skills/youtube-digest/extraction/setup-deps.mjs". Installs the pipeline's node dependencies into ${CLAUDE_PLUGIN_DATA} (persists across plugin updates); idempotent — safe to re-run, and re-run after a plugin update.winget install yt-dlp.yt-dlp (Windows), brew install yt-dlp (macOS), pip install -U yt-dlp or distro package (Linux). Acquisition throttling + bot-check cookie fallback: ## Gotchas
--js-runtimes node by default (set the yt_dlp_js_runtimes option to off to omit)watch only (scene-detect frame extraction). Floor 7.1+.watch only (contact sheets). magick -versionIf any prerequisite fails, stop and inform the user. Re-run setup-deps.mjs for the node dependencies; the media binaries (yt-dlp, ffmpeg, ImageMagick) are OS-level installs via your platform's package manager per the commands above.
Driver video: https://www.youtube.com/watch?v=7zZy1QTvokM — slug stop-prompting-claude-use-karpathy-s-met-7zZy1QTvokM.
| File | Role |
|---|---|
evals/evals.json | Skill behavior + driver golden eval cases |
evals/fixtures/driver-video-goldens.json | Q&A bank (≥1 frame_only question) |
evals/fixtures/variation-matrix-backlog.json | Code screencast / slide talk / talking-head / mixed — backlog only |
D9 starting defaults: ${CLAUDE_PLUGIN_ROOT}/vendor/video-digestion/TUNING.md. Retune after first host watch.
npx claudepluginhub melodic-software/claude-code-plugins --plugin knowledgeGuides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Creates platform-native content for X, LinkedIn, TikTok, YouTube, and newsletters from source material. Adapts voice and format per platform while avoiding engagement bait and filler.