Skip to content

Commit c61501e

Browse files
cizerclaude
andcommitted
feat(skills): add ingest-youtube skill
Pull a YouTube video's captions via yt-dlp, distil to a reference note, and file via vault-ingest conventions. Ported from PersonalVault's vault-local copy into the bundled set so it ships in the binary and materialises to both the Claude and Codex skills dirs. The VTT cleaner is inlined rather than a co-located script, so the skill is self-contained and resolves identically in every agent runtime; the manual reindex step is dropped to match the sibling ingest-* skills. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 06e49cd commit c61501e

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
---
2+
name: ingest-youtube
3+
description: >-
4+
Pull the transcript from a YouTube link and file distilled insights into the
5+
vault. Triggers on "/ingest-youtube", a pasted youtube.com or youtu.be link
6+
with intent to capture, "get the transcript", "extract insights from this
7+
video", "summarise this YouTube video into the vault", or any request to turn
8+
a YouTube video into a vault note. Runs in an interactive session
9+
(auto-caption-only videos need browser cookies, which can prompt the macOS
10+
keychain). Don't trigger when the user only wants a video summarised in chat
11+
with no filing, or for non-YouTube media.
12+
---
13+
14+
# Ingest YouTube
15+
16+
Acquisition and distillation layer for YouTube videos, a sibling to ingest-inbox
17+
(email) and ingest-meetings. It fetches a video's captions, distils them into
18+
useful notes, and files them. It **defers all filing conventions to the
19+
vault-ingest skill and all tone, folder, tag and privacy rules to the vault
20+
`CLAUDE.md`**. Do not duplicate that logic here; apply it.
21+
22+
Default to keeping **distilled insights only**, not the raw transcript, because
23+
the transcript is third-party content. Save the raw transcript alongside a note
24+
only if the user asks.
25+
26+
## Prerequisites
27+
28+
- `yt-dlp` via Python: check `python3 -m yt_dlp --version`. If missing, install
29+
with `python3 -m pip install --user --upgrade yt-dlp`.
30+
- The fetch step needs outbound network, so run it with the Bash sandbox
31+
disabled.
32+
33+
## Workflow
34+
35+
### 0. Anchor the date
36+
37+
Confirm today's date from session context and state it before stamping files.
38+
39+
### 1. Take the link(s)
40+
41+
Get the YouTube URL(s) from the user. Note the video id (the `v=` value or the
42+
`youtu.be/<id>` slug).
43+
44+
### 2. Fetch captions (no video download)
45+
46+
First attempt, no cookies (works for videos with manual captions):
47+
48+
```
49+
python3 -m yt_dlp --skip-download --write-subs --write-auto-subs \
50+
--sub-langs "en.*,en" --sub-format vtt -o "/tmp/ytt.%(ext)s" "<URL>"
51+
```
52+
53+
If yt-dlp reports *"a PO token was not provided"* or *"no subtitles for the
54+
requested languages"*, the video has auto-captions only and YouTube is gating
55+
them. Retry with the user's browser cookies. **Ask which browser first**
56+
(Chrome / Safari / Brave / Firefox), then add:
57+
58+
```
59+
--cookies-from-browser <browser>
60+
```
61+
62+
Warn that Chrome/Brave/Edge may trigger a one-time macOS "Safe Storage" keychain
63+
prompt the user must approve. Run this in the background so the keychain prompt
64+
does not block. Do not scan or enumerate browser cookie stores yourself; let
65+
yt-dlp read only what it needs from the single named browser.
66+
67+
### 3. Flatten the VTT
68+
69+
Strip the WEBVTT headers, cue timings, inline `<...>` tags and the
70+
rolling-duplicate lines auto-captions emit. This step is local (no network), so
71+
it runs under the normal sandbox. Use `*.en-orig.vtt` if `*.en.vtt` is absent.
72+
The helper is inlined so the skill is self-contained in any agent runtime:
73+
74+
```
75+
python3 - /tmp/ytt.en.vtt /tmp/ytt.txt <<'PY'
76+
import re, sys
77+
raw = open(sys.argv[1], encoding="utf-8").read()
78+
lines = []
79+
for ln in raw.splitlines():
80+
s = ln.strip()
81+
if not s or s.startswith(("WEBVTT", "NOTE", "Kind:", "Language:")) or "-->" in s:
82+
continue
83+
s = re.sub(r"<[^>]+>", "", s).replace("&nbsp;", " ").strip()
84+
if s and (not lines or s != lines[-1]):
85+
lines.append(s)
86+
out = []
87+
for ln in lines:
88+
if out and (ln == out[-1] or out[-1].endswith(ln)):
89+
continue
90+
out.append(ln)
91+
text = re.sub(r"\s+", " ", " ".join(out)).strip()
92+
open(sys.argv[2], "w", encoding="utf-8").write(text + "\n")
93+
sys.stderr.write(f"words={len(text.split())} chars={len(text)}\n")
94+
PY
95+
```
96+
97+
It prints the word and character count to stderr.
98+
99+
### 4. Distil
100+
101+
Read the cleaned transcript. Produce a **reference note**, not a transcript
102+
dump: the video title and a source link, a one or two line summary, the key
103+
ideas/practices, and, for coaching or learning material, concrete prompts or
104+
takeaways the user can reuse. Keep British English, concise and plain per
105+
`CLAUDE.md`.
106+
107+
### 5. File via vault-ingest conventions
108+
109+
Place per PARA: coaching/learning usually `2-Areas/Personal Development/` or
110+
`3-Resources/`. Title Case filename. Frontmatter with `title`, `tags`
111+
(type + domain, e.g. `[reference, personal-development, coaching]`), the `source`
112+
URL, and `created`. Add `[[wiki links]]` to related notes. Apply the CLAUDE.md
113+
privacy rules (a private-area topic stays factual and unshared).
114+
115+
### 6. Log
116+
117+
If the vault keeps an ingest log, append a row (newest first, matching the log's
118+
schema): `date | title | folder | tags | source (YouTube <id>) | private`. No
119+
manual reindex: new and changed notes (including the log row) are picked up by
120+
the index on the next search, and the file watcher reindexes live edits;
121+
`mcp__hebb__reindex_vault` is only an escape hatch for a suspected-stale index.
122+
123+
### 7. Clean up
124+
125+
Remove the `/tmp/ytt.*` artefacts. Do not commit or push: if the vault runs a
126+
hebb sync job it auto-commits and pushes new content, so a manual commit just
127+
races it. (Only if a vault has no sync job, tell the user the change is
128+
uncommitted and let them decide.)
129+
130+
## Notes
131+
132+
- Manual-caption videos need no cookies; auto-caption-only videos do.
133+
- For several links, loop the same steps; dedupe by video id against the ingest
134+
log.

0 commit comments

Comments
 (0)