Install
$ agentstack add skill-codexis-claude-media-skills-media-distill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
YouTube → Zettelkasten
Turns a YouTube video into an atomic Zettelkasten note and stores it under Video/.
When to use
- User sends a YouTube URL and asks for a summary / note / recap.
- User says "save this", "make a note", "bookmark this", "save for later", "just export" about a video.
- You need to distill knowledge from a lecture, podcast, or tutorial.
Determining status from the user's command
Status is derived from the meaning of the message or from a short command prefix before the link.
| Command | Synonyms / intent | status | |----------------------|-------------------------------------------------|--------------| | w , s | "save", "make a note", "watched" | watched | | b | "bookmark", "save for later", "watch later" | bookmarked | | a | "archive", "just export", "source", "mentioned" | archived |
If no command prefix is given — infer from the phrasing. Default: watched.
Configuration
Edit these settings directly in this file before using the skill.
| Setting | Default | Description | |--------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | VAULT_ROOT | . | Path to your Obsidian vault root (where Video/, Book/, Person/, Author/ folders live). Can be absolute or relative to the repo root. Example: ~/notes or /home/user/vault. | | NOTE_LANG | transcript | Language for note content. transcript = match the video's transcript language. Or set a fixed locale: en, ru, de, etc. | | TRANSCRIPT_LANGS | ru,en | Comma-separated preferred transcript languages passed to --lang. Order = priority. | | PYTHON | python3 | Python executable to use. Change to .venv/bin/python3 if using a local venv. |
Current values:
VAULT_ROOT = .
NOTE_LANG = transcript
TRANSCRIPT_LANGS = ru,en
PYTHON = python3
To reconfigure — edit the three lines inside the code block above. No other files need to change.
Dependencies
pip install -r .claude/skills/media-distill/scripts/requirements.txt
Handling multiple URLs
If the user's message contains several YouTube URLs — process each one sequentially, creating a separate note per URL using the process below. Report intermediate progress to the user.
Playlists, shorts, live
- Shorts (
/shorts/) — treated as regular videos. - Playlists (
?list=...) — not supported. Ask the user for a specific video URL from the playlist. - Live recording — treated as a regular video if subtitles are available. For an active live stream the transcript is usually unavailable.
Process (step by step)
1. Fetch transcript and metadata
.claude/skills/media-distill/scripts/youtube_export.py --lang
The script prints JSON to stdout:
{
"video_id": "abc123",
"url": "https://www.youtube.com/watch?v=abc123",
"transcript": "full text...",
"lang": "ru",
"title": "Video title",
"channel": "Channel name",
"upload_date": "2024-03-15",
"duration_sec": 1080,
"channel_url": "https://www.youtube.com/channel/UC...",
"channel_name": "Channel name",
"channel_handle": "@handle",
"channel_description": "Channel description...",
"safe_title": "Video title",
"safe_channel_name": "Channel name"
}
On error — a message in stderr, exit code 1.
The transcript is not saved to the vault as a separate file — it is only used to generate the note, then discarded.
Channel metadata is cached in scripts/.cache/cache.sqlite (30-day TTL) — repeated videos from the same channel reuse cached data. The cache file is gitignored.
2. Check for filename collisions
Before creating Video/.md, check whether the file exists.
If the file exists — ask the user via AskUserQuestion:
- Skip — note already exists, do nothing.
- Overwrite — recreate the note (manual edits will be lost).
- Add video_id suffix — create
Video/ ().md.
Same rule applies to Book/.md. For Person/ and Author/ a collision simply means "file exists" and should not be overwritten (see §3 and §4).
3. Check and create the Person note
Use safe_channel_name from the JSON as both the filename and the wikilink target.
Check whether Person/.md exists:
- If it exists — continue, use
[[]]as the author reference. The Person note is not overwritten (even ifchannel_descriptionhas changed). - If missing — create it from
.claude/skills/media-distill/templates/person.md, substituting fields from the JSON.
Placeholders in person.md:
| Placeholder | Source (JSON) | |---------------------------|---------------------------------------------------| | {{channel_handle}} | channel_handle (channel handle, @name format) | | {{channel_url}} | channel_url | | {{channel_description}} | channel_description |
4. Create the Video note
Pick the template by status:
| status | Template | |--------------|-------------------------------------------------------------------------------------------------------------------------------| | watched | .claude/skills/media-distill/templates/video.md (full distillation) | | bookmarked | .claude/skills/media-distill/templates/video.md (full distillation — produce it now, even if the user hasn't watched yet) | | archived | .claude/skills/media-distill/templates/video-archived.md (minimal stub — export book/author notes, skip video distillation) |
Placeholders (both video.md variants):
| Placeholder | Source | |-------------------------|-------------------------------------------------------------------------------| | {{url}} | url from JSON | | {{safe_channel_name}} | safe_channel_name from JSON (sanitized — must match the Person/ filename) | | {{upload_date}} | upload_date from JSON (video publish date, YYYY-MM-DD) | | {{save_date}} | today's date in YYYY-MM-DD | | {{status}} | watched / bookmarked / archived (from user command) | | {{duration_sec}} | duration_sec from JSON | | {{lang}} | lang from JSON (transcript language) | | {{title}} | title from JSON (original title used as the note heading) |
Filename: Video/.md (field safe_title from the JSON).
Requirements for full-distillation notes (watched / bookmarked):
- Note language = determined by
NOTE_LANG(see Configuration). Iftranscript— use the video's transcript language (langfield). If a fixed locale is set — write the entire note in that language regardless of the transcript. - Each idea is atomic: one section = one thought.
- No retelling — only distillation of meaning.
- Tags as
#word, wikilinks as[[concept]]. - Forward-wikilinks on books/authors (
[[Book Title]],[[Author Name]]) in the body are the trigger for step 5. Write them in the source language as they sound in the video — do not try to guess the canonical English title. Alias resolution happens in step 5.
Requirements for archived notes:
- 1–2 sentences of context — why this note exists as a source (what is referenced, what it links to).
- No "Key ideas", "Practice", "Related" sections — the note is a stub for backlinks.
- Primary purpose: capture book/author references so step 5 runs and Book/Author notes are saved.
- If the video mentions books: populate the "Books mentioned" section — one line per book in the format
[[Title]] — [[Author Name]]. Write the title and author as they appear in the video (source language); step 5 resolves them to canonical filenames. If no books — omit the section entirely.
5. Post-process — book/author references
Trigger: any forward [[...]] wikilink in the Video note body (context sentence for archived, body / Related section for watched / bookmarked) that points to a book or a book's author. Always run this step when such wikilinks exist — book notes are saved unconditionally.
Action: for each such wikilink pass through book-flow.md, passing the tentative name (exactly as written in the wikilink) as the input. Several books in one video → one pass per book.
Wikilink rewrite. After book-flow.md finishes and the canonical Book/Author filenames are known, rewrite each matching wikilink in the Video note to Obsidian pipe syntax [[canonical|tentative]] — e.g. [[La Cinquième Discipline]] → [[The Fifth Discipline|La Cinquième Discipline]]. Reason: Obsidian does not auto-resolve [[alias]] through the aliases: frontmatter field inside wikilinks; the pipe form is required for the link to navigate to the canonical file while keeping the source-language display. If tentative == canonical, leave the wikilink as is.
Common errors
| Error | Cause | Resolution | |-------------------------------|----------------------------------------|---------------------------------------------------| | 403 Forbidden | YouTube is blocking the IP | Run locally, not in CI/cloud | | TranscriptsDisabled | Author disabled captions | Transcript unavailable | | NoTranscriptFound | No captions for the requested language | Add --lang en | | Empty transcript | Private video or no captions | Check video availability | | Sign in to confirm your age | Age-restricted | Inform the user — the script does not bypass auth |
Skill files
media-distill/
├── SKILL.md ← this file (video flow, triggers, common errors)
├── book-flow.md ← book recommendations flow (templates, list/null fields)
├── templates/
│ ├── person.md ← template for Person/
│ ├── video.md ← template for Video/ (watched / bookmarked)
│ ├── video-archived.md ← template for Video/ with status: archived
│ ├── author.md ← template for Author/
│ └── book.md ← template for Book/
└── scripts/
├── youtube_export.py ← fetches video/channel data
├── book_lookup.py ← looks up book metadata
├── cache.py ← SQLite cache for channel metadata (30-day TTL)
├── utils.py ← sanitize_filename() — shared helper
├── requirements.txt ← dependencies
└── .cache/ ← cache.sqlite (runtime, gitignored)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: codexis
- Source: codexis/claude-media-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.