$npx -y skills add tuan3w/obsidian-vault-agent --skill courseProcess an online course into detailed vault notes — one per lecture, with slides and transcripts synthesized. Use this skill whenever the user shares a course URL, syllabus page, or lecture playlist and wants structured notes from it. Also triggers on "process this course", "tak
| 1 | <Purpose> |
| 2 | Two modes: |
| 3 | |
| 4 | **Process mode** (default): Crawl an online course page, extract the lecture |
| 5 | schedule with all materials (slides PDFs, YouTube videos, readings), then |
| 6 | process each lecture into a detailed vault-formatted note with embedded slide |
| 7 | images and synthesized transcripts. Creates a Course index note linking |
| 8 | everything together. |
| 9 | |
| 10 | **Refine mode**: Re-read existing course lecture notes and improve them — |
| 11 | deepen equation explanations, add missing analogies, fix structure, strengthen |
| 12 | cross-references. Triggered when user says "refine", "improve", "fix", or |
| 13 | references existing course notes rather than a URL. |
| 14 | |
| 15 | This is an orchestrator — it coordinates downloading, extraction, and synthesis |
| 16 | across multiple lectures, producing a complete course knowledge package in the |
| 17 | vault. |
| 18 | </Purpose> |
| 19 | |
| 20 | <Use_When> |
| 21 | - User shares a course URL (syllabus, schedule, or homepage) |
| 22 | - User says "process this course" or "take notes on these lectures" |
| 23 | - User pastes a university course page with a lecture list |
| 24 | - User wants to batch-process a series of lectures from one course |
| 25 | - User has a YouTube playlist of course lectures |
| 26 | - User wants to refine/improve existing course notes ("refine mit diffusion notes", "improve L03") |
| 27 | </Use_When> |
| 28 | |
| 29 | <Do_Not_Use_When> |
| 30 | - User has a single YouTube video (use /youtube) |
| 31 | - User has a single local video file (use /lecture) |
| 32 | - User wants to process an existing vault note that's NOT a lecture (use /process) |
| 33 | - User wants a single paper summarized (use /paper) |
| 34 | </Do_Not_Use_When> |
| 35 | |
| 36 | <Steps> |
| 37 | |
| 38 | ## Stage 1: CRAWL — Extract the Lecture List |
| 39 | |
| 40 | Parse the course URL from $ARGUMENTS. If no URL, ask the user. |
| 41 | |
| 42 | Fetch the course page and extract structured lecture data: |
| 43 | |
| 44 | ``` |
| 45 | WebFetch( |
| 46 | url="COURSE_URL", |
| 47 | prompt="Extract the complete course structure as JSON. For each lecture/session, include: |
| 48 | - number (int) |
| 49 | - title (string) |
| 50 | - date (string, if available) |
| 51 | - slides_url (string or null — look for PDF links to slides/lecture notes) |
| 52 | - video_url (string or null — look for YouTube links) |
| 53 | - readings (array of {title, url} — papers, blog posts, textbook chapters) |
| 54 | - description (string or null — any summary text) |
| 55 | Also extract: |
| 56 | - course_title (string) |
| 57 | - course_code (string or null) |
| 58 | - instructors (array of strings) |
| 59 | - course_url (string — the page URL) |
| 60 | - course_notes_url (string or null — if there's a single PDF of all course notes) |
| 61 | Return ONLY valid JSON, no markdown fencing." |
| 62 | ) |
| 63 | ``` |
| 64 | |
| 65 | Parse the JSON response. If the page has relative URLs for slides/videos, resolve |
| 66 | them against the course URL's base. |
| 67 | |
| 68 | **Handle edge cases:** |
| 69 | - If the page is a YouTube playlist: extract video IDs and titles from the playlist |
| 70 | - If slides URLs are relative (e.g., `../docs/lecture_01.pdf`): resolve to absolute URLs |
| 71 | - If no structured schedule found: ask user to provide lecture list manually |
| 72 | |
| 73 | ## Stage 1b: DERIVE COURSE TAG |
| 74 | |
| 75 | Generate a short, memorable course hashtag from the course code or title. |
| 76 | This tag will be used consistently across ALL notes for this course. |
| 77 | |
| 78 | Rules for the tag: |
| 79 | - Use a descriptive short slug from the course topic, not just the code |
| 80 | - The tag should tell you what the course is ABOUT at a glance |
| 81 | - Examples: `#mit-diffusion`, `#cs231n-vision`, `#stanford-rl`, `#fast-ai-dl` |
| 82 | - Format: `institution-topic` or `code-topic` — lowercase, hyphens |
| 83 | - Keep it under 20 characters — short enough to type, long enough to understand |
| 84 | - Confirm the tag with the user before proceeding |
| 85 | |
| 86 | Also derive a COURSE_SLUG for asset folder naming (same as tag without `#`). |
| 87 | Example: assets folder `assets/mit-diffusion/`, tag `#mit-diffusion`. |
| 88 | |
| 89 | ## Stage 2: PLAN — Confirm Scope with User |
| 90 | |
| 91 | Present the extracted lecture list to the user in a clear table: |
| 92 | |
| 93 | ``` |
| 94 | Found N lectures for "Course Title": |
| 95 | Course tag: #6s184 |
| 96 | Assets folder: assets/6s184/ |
| 97 | |
| 98 | | # | Title | Slides | Video | Readings | |
| 99 | |---|-------|--------|-------|----------| |
| 100 | | 1 | Topic | PDF | YT | 2 papers | |
| 101 | | 2 | Topic | PDF | — | 1 paper | |
| 102 | ... |
| 103 | |
| 104 | Which lectures should I process? (default: all) |
| 105 | Options: "all", "1-3", "1,3,5", or specific numbers |
| 106 | ``` |
| 107 | |
| 108 | If $ARGUMENTS includes a range (e.g., "1-3"), skip confirmation and use that range. |
| 109 | |
| 110 | ## Stage 3: PROCESS — Handle Each Lecture |
| 111 | |
| 112 | ### Content Source Priority |
| 113 | |
| 114 | Not all sources are equal. A 50-minute video transcript wh |