| name | add-recipe |
| description | Add web recipes and cooking videos (YouTube, TikTok, Instagram Reels, Facebook Reels, Vimeo) to the user’s Obsidian recipes vault with proper frontmatter, auto-detected tags, hero image extraction, and consistent formatting. Trigger when the user says “add this to my recipes”, “/add-recipe”, pastes a recipe URL, or wants to save recipe content to their vault. Also handles “/add-photo {recipe title}” for retroactively adding a hero image to an existing recipe. |
Add Recipe to Obsidian Vault
Add web recipes and cooking videos (YouTube, TikTok, Instagram Reels, Vimeo) to the user’s Obsidian recipes vault with proper frontmatter, auto-detected tags, hero image extraction, and consistent formatting. The vault lives at {VAULT_ROOT}\.
This skill is a router. The actual workflow lives in reference files that get loaded based on the URL type and the operation being performed. The reasoning: a typical web-recipe URL doesn’t need to load the YouTube transcript-extraction logic, and vice versa, so we pull in only what’s relevant.
Entry points
This skill has two distinct invocation patterns:
| Command | Purpose |
|---|
/add-recipe [tags...] [url or pasted content] | Add a new recipe to the vault |
/add-photo "{recipe title}" | Add a hero image to an existing recipe that lacks one |
If the user’s request matches /add-photo or describes “add a photo to {existing recipe}”, jump directly to the /add-photo workflow section near the bottom of this file. Otherwise, proceed through Step 0.
How to use this skill (for /add-recipe)
A typical invocation looks like one of these:
/add-recipe https://example.com/recipe
/add-recipe meal-prep https://example.com/recipe
/add-recipe meal-prep quick https://example.com/recipe
add this recipe: https://example.com/recipe
add this to my [cuisine] recipes: https://example.com/recipe
Plus the same patterns with video URLs (YouTube, TikTok, Instagram Reels, Vimeo) or pasted recipe text.
Step 0: Parse arguments and detect URL type
Before loading any reference files, parse the input and classify what’s there.
Step 0a: Extract manual tags
Tokenize the input after /add-recipe (or the equivalent natural-language invocation). Walk tokens left-to-right:
- If a token starts with
http://, https://, youtube.com, youtu.be, tiktok.com, instagram.com, or vimeo.com → stop. Treat this token and everything after as the URL/content.
- Otherwise → treat the token as a manual tag candidate and continue.
For pasted recipe text (no URL present): tokens before the first blank line are tag candidates; everything after is the recipe content.
For each manual tag candidate, load references/tag-vocabulary.md and look it up:
- If it matches a shorthand in the vocabulary → use the canonical form (e.g.,
meal-prep → prep/meal-prep)
- If it matches a canonical tag directly (e.g.,
prep/meal-prep) → use as-is
- If it’s unknown → ask the user: ”
{token} isn’t in the vocabulary. Did you mean {closest-match}? Or add {token} as a new tag?” Do not proceed until resolved. If the user confirms adding it as new, append the new shorthand-to-canonical mapping to tag-vocabulary.md before continuing.
Keep the resolved manual tags in scope for Step 2.
Step 0b: Detect URL type
Classify the URL (or content) the user provided:
| URL contains | Source type | Reference to load |
|---|
youtube.com/watch, youtu.be/, youtube.com/shorts/ | Video (long-form) | references/video-workflow.md |
tiktok.com/, instagram.com/reel/, instagram.com/p/, facebook.com/reel/, facebook.com/share/r/, fb.watch/, vimeo.com/ | Reel (short-form social) | references/reel-workflow.md |
| Anything else (blog, recipe site, etc.) | Web article | references/web-workflow.md |
| No URL — pasted recipe text | Pasted | references/web-workflow.md (treat the text as if it were the extracted result) |
If the URL is ambiguous, default to web. If web_fetch returns a video page rather than a recipe, escalate to the video workflow.
Step 1: Load the workflow reference
Based on Step 0b, view the corresponding workflow file. The workflow file contains the full set of substeps for that source type — fetching, extracting, handling failures, and the confidence-gate logic for video sources.
- Video URLs (YouTube long-form / Shorts) →
view references/video-workflow.md
- Reel / short-form social URLs (IG, TikTok, FB, Vimeo) →
view references/reel-workflow.md
- Web URLs (or pasted text) →
view references/web-workflow.md
The workflow file will tell you when you have enough information to proceed to image extraction and tagging.
Step 1.5: Extract hero image
Once the workflow has produced the recipe’s title and source content, load:
view references/image-extraction.md
Follow the priority chain defined there:
- JSON-LD Recipe schema
image field
<meta property="og:image">
<meta name="twitter:image">
- YouTube thumbnail (
maxresdefault.jpg → hqdefault.jpg → mqdefault.jpg) for video sources
- First large
<img> in article content (filtered)
- Graceful fallback — save with
image_missing: true and prompt the user to paste or use /add-photo later
Apply the quality filter (file size, dimensions, aspect ratio, MIME type) to every candidate before accepting it. Resize, re-encode, and save to {VAULT_ROOT}/attachments\{slug}.{ext} per the rules in the reference file.
Do not block the recipe save if image extraction fails. Save with image_missing: true and report the gap in the confirmation message at Step 5.
Step 2: Tag the recipe
Load the tagging rules:
view references/tagging-rules.md
Apply the rules to determine the auto-detected tags across all defined namespaces: cuisine/, protein/, diet/, method/, type/, and prep/. Run the self-check before moving on.
Merge with manual tags from Step 0a:
- Manual tags from the command add to (do not replace) auto-detected tags
- Dedupe the combined set
- Write the final tag list to frontmatter
The tagging rules are the same regardless of whether the source was a video or a web page.
Step 3: Pick the folder
Load the vault structure reference to pick the target folder:
view references/vault-structure.md
If the user specified a category in their request (e.g., “add this to my wok recipes”), honor that over auto-detection.
Step 4: Format and write the file
Load the file format reference for the frontmatter template, body structure, and output rules:
view references/file-format.md
The format file has separate templates for web sources and video sources (they differ only in frontmatter — video adds video_url, creator, and optionally calories / protein). Both templates now include the image frontmatter fields (image:, image_source:, or image_missing:) and the ![[attachments/...]] body embed when an image is present.
Then use Filesystem:write_file to save to:
{VAULT_ROOT}\[Category]\[Recipe Title].md
Step 5: Confirm to user
Report a concise summary:
- File path where the recipe was saved
- Auto-detected tags grouped by category, plus any manual tags applied
- Quick facts (total time, servings)
- Source (channel name for video, site name for web)
- Image status — whether an image was extracted (and from which source) or whether
image_missing: true was set
Mention any borderline tag calls so the user can override during the same conversation if needed. For video sources where the workflow’s confidence gate fired, note that uncertain values were flagged in the file.
If image_missing: true was set, include a prompt in the confirmation:
⚠️ No image found. Paste one now to add it, or run /add-photo "{recipe-title}" later.
If the user pastes an image in their next message, treat it as a /add-photo invocation for this recipe and follow that workflow.
Example confirmation — web source with image
**Recipe added to vault**
Saved to: `{VAULT_ROOT}/Wok\Pork & Holy Basil Stir-fry (Pad Kra Pao).md`
**Tags:**
- cuisine/thai
- protein/pork
- diet/spicy
- method/wok, method/stir-fry
- type/main-dish
- prep/meal-prep *(manual)*
**Image:** attachments/pork-holy-basil-stir-fry.jpg (source: scraped via og:image)
**Quick facts:**
- Total time: 15 minutes (10 prep + 5 cook)
- Serves: 4
- Source: Marion's Kitchen
Example confirmation — image missing
**Recipe added to vault**
Saved to: `{VAULT_ROOT}/Stovetop\Lemon Chicken Piccata.md`
**Tags:**
- cuisine/italian
- protein/chicken
- diet/citrus
- method/stovetop
- type/main-dish
⚠️ No image found. Paste one now to add it, or run `/add-photo "Lemon Chicken Piccata"` later.
**Quick facts:**
- Total time: 25 minutes
- Serves: 4
- Source: example.com
Example confirmation — video source
**Recipe added to vault** (from video)
Saved to: `{VAULT_ROOT}/Baked Food\BBQ Chicken Sheet Pan Pizza.md`
**Tags:**
- cuisine/american
- protein/chicken
- method/baked
- type/pizza
**Image:** attachments/bbq-chicken-sheet-pan-pizza.jpg (source: YouTube thumbnail)
**Quick facts:**
- Active prep: 20 min · Cook: 24 min · Total (incl. rises): ~3 hours
- Serves: 8 slices
- Source: Exercise4CheatMeals (YouTube)
/add-photo workflow
Triggered by /add-photo "{recipe title}" or natural-language equivalents like “add a photo to my Chicken Tikka Masala recipe.”
Step P1: Locate the recipe
Search {VAULT_ROOT}\ recursively for .md files whose title (from frontmatter title: field or filename) matches the user’s input. Use case-insensitive partial matching.
- Exactly one match: proceed to Step P2 with that file.
- Multiple matches: list them with their folder paths and ask the user to pick.
- No matches: report that no recipe was found and suggest the user check the title spelling or use
/add-recipe if they meant to add a new one.
Step P2: Prompt for the image
Once the target file is identified, prompt the user:
Paste a photo for {recipe title} in your next message, or reply skip to abort.
Wait for the next user message. Do not modify the file yet.
Step P3: Handle the response
- User pastes an image: apply the user-provided image flow from
references/image-extraction.md (resize, save to attachments/, derive filename from the recipe’s slug, handle filename collisions with -2/-3 suffixes).
- User replies
skip (or sends non-image text): abort cleanly, make no changes to the file, confirm the abort.
Step P4: Update the recipe file
If an image was provided in Step P3:
- Read the current file content
- Update frontmatter:
- Add or replace
image: attachments/{filename}
- Set
image_source: user-provided
- Remove
image_missing: true if present
- Remove
image_source: none if present
- Insert
![[attachments/{filename}]] on the line immediately after the closing --- of frontmatter, if no embed is already there. If an embed is already present but points to a different file, replace it.
- Write the updated file back to the same path
Step P5: Confirm to user
**Photo added**
Recipe: `{VAULT_ROOT}/Stovetop\Lemon Chicken Piccata.md`
Image: attachments/lemon-chicken-piccata.jpg (source: user-provided)
If aborted at Step P3 (user replied skip):
No changes made to `{VAULT_ROOT}/Stovetop\Lemon Chicken Piccata.md`.
Edge cases
For rare situations (paywalled web pages, videos with no transcript, multi-recipe compilation videos, non-English transcripts, TikTok/Reels minimal text, HEIC pasted from iPhone), load:
view references/edge-cases.md
Don’t load this preemptively — only when the workflow files explicitly point you at it.
Important notes
- The vault lives at
{VAULT_ROOT}\.
- The skill now extracts hero images automatically — the user no longer adds images manually unless auto-extraction fails.
- All recipe images go to
{VAULT_ROOT}/attachments\.
- Use today’s date for
date_added in frontmatter (YYYY-MM-DD format).
- When the user specifies a cuisine or category in their request, honor that over auto-detection.
- When the user specifies manual tags via
/add-recipe meal-prep ..., apply them in addition to auto-detected tags.
- Ingredient amounts use unicode fractions where appropriate (⅓, ½, ¼, ¾).
- The vault has periodic audit scripts (
_audit_recipes.py and _apply_fixes.py) at the vault root. The audit script recognizes the new image frontmatter fields (image, image_source, image_missing) and the new prep/ tag namespace. The tagging rules in this skill should match what those scripts check.
- The
prep/ namespace currently contains only prep/meal-prep. Do not invent additional prep/* tags without first adding them to references/tag-vocabulary.md and references/tagging-rules.md.
- When fetching images during web extraction, use a realistic User-Agent header (
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36).
- For pasted recipe text without a URL, image extraction Steps 1–5 are skipped — go directly to Step 6 (prompt user for image) or save with
image_missing: true.
- Reel sources (IG, TikTok, FB, Vimeo) add three new frontmatter fields:
source_platform, extraction_confidence (high / medium / low), and extraction_issues (list). Update the audit scripts (_audit_recipes.py) to recognize these on the next pass.
- For reel extraction, public content only — never bypass logins, paywalls, or private-account gates. If a reel is inaccessible, fall through to user-provided screenshots or pasted text per
references/reel-workflow.md Step 6R.