talks-outline — exhaustive outlines of talks, in parallel, exported as markdown
Every run ends with one .md file per talk in ~/Downloads/talks-outlines/summaries/ plus a
row in talks-outline-index.md. The outline is the deliverable; the chat reply is just the
index.
Depth is the whole point — a thin, table-heavy summary is a failure (see Depth bar).
Inputs
| Input | How handled |
|---|---|
| YouTube link(s) / playlist | fetched via scripts/fetch_transcript.py (Claude Code, or any env with network to YouTube) |
A urls.txt file (one URL/line, optional domain and filename columns) |
seeded into the queue with scripts/talks-queue.sh seed-urls |
work-queue (continue an already-seeded queue) |
claim-loop only; no new seeding |
| Transcript pasted in the message | save to ./talks-work/<slug>/transcript.txt, then outline |
Uploaded .txt/.md/.pdf/.docx transcript |
read it (file-reading skill if needed), save as above |
| An existing outline folder to re-enrich (Mode B) | seeded with seed-dir; filenames and index left untouched |
If a link can’t be fetched (no network, no captions), skip it, record it under Skipped in the index, mark it done in the queue, and continue. Never outline from a title alone.
Two modes
- Mode A — new work. URLs/transcripts with no existing outline -> create one
.mdper talk and append a row totalks-outline-index.md. - Mode B — re-enrich. The user points at existing outline files that are thin -> rewrite each body in place to meet the depth bar, keep the existing filename, and do not add index rows (update the row’s Summarized date only if asked).
Both run the same pipeline and depth bar; they differ only in seeding and whether new index rows are added. Auto-detect: bare links -> A; “re-enrich/improve these” or a folder of existing outlines -> B.
Unattended mode — never ask, always decide
Often run while the user is away. Do not use AskUserQuestion, do not end a turn with a question, do not wait for confirmation. Resolve every ambiguity with these defaults and note the choice in the index:
| Situation | Default |
|---|---|
| Domain unclear | auto; the worker decides from the transcript |
| Language | the transcript’s spoken language (see Language rule) — never from title/channel |
| Playlist > 30 videos | queue the first 30 in order; list the rest under Not processed |
| Fetch fails / no captions | retry once, then skip + log + mark done |
| Worker fails or returns partial | reset the row once; if it fails again, log under Failed |
| Outline file already exists (same day) | overwrite; a later day makes a new dated file |
| Zero links or transcripts found | write nothing; reply one line saying no input was found |
| Missing Python deps | print the one-time setup from README.md and stop; never auto-install |
| Only an unsafe/impossible request ends the run early — and even then finish the other talks. |
Workflow
1. Collect & seed the queue
Extract every YouTube URL (watch?v=, youtu.be/, shorts/, live/, embed/,
playlist?list=) and every pasted/attached transcript. Expand a playlist first:
<skill-dir>/.venv/bin/python <skill-dir>/scripts/fetch_transcript.py --expand <url>.
Seed the shared queue (one source of truth, safe for many agents):
export QUEUE_TSV=/tmp/talks-queue.tsv
<skill-dir>/scripts/talks-queue.sh seed-urls <urls.txt> # from a file
# or, for a handful of links, write them to a temp file and seed that
<skill-dir>/scripts/talks-queue.sh seed-dir ~/Downloads/talks-outlines/summaries # Mode BEach row is id<TAB>filename<TAB>domain<TAB>Pending; filename=PENDING_TITLE means the
worker derives it. Seeding is idempotent — already-queued ids are skipped, so re-seeding a
growing urls.txt is safe. For pasted/uploaded transcripts there is no id to fetch: write
the transcript + a meta.json yourself and outline directly (no queue needed for a single
paste).
2. Outline — parallel workers claiming the queue
Subagents available (Claude Code, Cowork): spawn talks-outliner once per worker slot,
all in one turn (4–6 slots — YouTube rate-limits beyond that), each with a unique tag. Each
worker loops: claim -> fetch -> exhaustive outline -> enrich pass -> single-write ->
index row -> done, until QUEUE_EMPTY. Do not fetch or outline in the main session.
Delegation prompt per worker:
Work the talks queue until empty. Your tag: <worker-N>.
- Queue helper: <skill-dir>/scripts/talks-queue.sh (export QUEUE_TSV=/tmp/talks-queue.tsv)
- Fetcher: <skill-dir>/.venv/bin/python <skill-dir>/scripts/fetch_transcript.py
- Out dir: ~/Downloads/talks-outlines/summaries
- Mode: <A create+index | B re-enrich, keep filename, no new index row>
- Follow references/outline-format.md exactly (depth bar). Language = spoken language.
- Return only: talks completed, files written, total [E] flags, or FAILED <reason>.
<any extra user instructions, verbatim>No subagents (Claude.ai web / mobile): fetch in parallel, then outline each talk yourself sequentially at full depth:
<skill-dir>/.venv/bin/python <skill-dir>/scripts/fetch_transcript.py --out ./talks-work --jobs 4 <url> ...3. Export — mandatory
- One
.mdper talk in~/Downloads/talks-outlines/summaries/(expand~, create if missing). This is the single collection point across all projects — never write into the current repo. - Mode A filename:
<slug>-<YYYY-MM-DD>.md(slug = 4–6 title words, kebab, ASCII; date = day produced). Mode B: keep the existing filename exactly. - Index: append/update
~/Downloads/talks-outlines/summaries/talks-outline-index.mdunderflock /tmp/talks-index.lock(the only shared-write file). Columns: Summarized date, Talk title, Speaker/channel, Domain, Lang, Outline link, Video link. Skipped / Failed / Not-processed go in a second table with reasons. Newest rows at the top of the body. - Claude.ai: write to
/mnt/user-data/outputs/and callpresent_fileson every outline and the index so the user gets download cards.
4. Reply
Short: the index table (or one line for a single talk), the file names, and one sentence on
the most important [E] or critical observation. Don’t paste outline bodies into chat.
Depth bar (the point of the whole exercise)
Depth comes from granularity, not word count. Enforced in references/outline-format.md;
as orchestrator, before accepting a worker’s file confirm it has:
- A framing blockquote (speaker, venue, format, the talk’s own structure).
- A deep decimal hierarchy — one
###per distinct sub-topic/example/step; a long talk has 25+###, not 3. Enumerations (patterns, steps, rules, companies) each get their own numbered###; a summary table may add to but never replace the per-item sections. - One idea per bullet. Worked examples decomposed step by step. Q&A one
###per question (Q5/Q5a), asker named. Quotes attributed, each under 15 words. - A “People & References Cited” index at the end; exact provenance footer.
- Shape matches the talk: a 90-min workshop -> very long; a narrative keynote is shorter at the same fidelity — expected, not a defect. Panels/podcasts -> topic-threaded; if a guest was absent, say so, never fabricate.
Plus the analytical layer this skill adds on top of the playbook: claim tags [V] verifiable
· [D] speaker estimate · [P] pending · [E] error/contradiction; a Critical
observations section (analysis not in the talk); a Pending verification table. If a
worker’s file misses any of this, reset its row or message it to fix the file.
Language rule
Transcript and outline are in the language spoken in the talk. The fetcher only ever
saves original-language captions (manual first, else auto), so meta.json language is the
spoken language; the worker verifies against the body and trusts the body on conflict. Write
the entire file in that language — headers, tables, tags, observations. Vietnamese talk ->
Vietnamese transcript and file; Japanese -> Japanese. Only an explicit user override changes
it, and then the header records “translated from
Parallel-safety rules
- The queue TSV is mutated only through
talks-queue.sh(flock-serialized) — never hand- edit it while workers run. - The index is the one shared-write file — always
flock /tmp/talks-index.lock, briefly. - Writing different outline files concurrently needs no lock.
- Each outline is written in one write, never incrementally.
- Locks (queue, index) are separate and never nested; held only for their tiny section.
- A crashed worker leaves a row
In Progress;talks-queue.sh reset <id>requeues it. - Transcripts are scratch in
/tmp(or./talks-work/) — never committed anywhere.
Cross-AI batches
Any agent (Codex CLI, Gemini CLI, Cursor, a second machine) can join the same queue: give it
a unique tag and AGENT-BRIEF.md (self-contained — full depth bar, language rule, file
format, locking). See USAGE.md for launch commands and AGENT-BRIEF.md for the worker
contract.
Files in this skill
scripts/fetch_transcript.py— original-language transcript + metadata fetcher, playlist expander, parallel--jobsscripts/talks-queue.sh— flock-serialized work queue (seed-urls / seed-dir / claim / done / reset / status / stats)references/outline-format.md— the depth bar and per-domain section blocks (worker preloads this)agents/talks-outliner.md— subagent worker definition; copy to~/.claude/agents/AGENT-BRIEF.md— paste into non-Claude agents so they can work the queueUSAGE.md— end-to-end multi-agent run guide