Files
recipes/docs/specs/2026-05-21-recipe-images-design.md

3.4 KiB

Recipe Image Ingestion Spec

Goal: Give every .cook recipe file in the repository a high-quality, relevant food image hosted at https://roux.roo.lol/recipe-images/ and referenced in its YAML frontmatter.

Scope

Category Count Action
Has YAML frontmatter + already has image: 19 Download existing image, re-host, update URL
Has YAML frontmatter + no image: 48 Find + download image, add image: field
No YAML frontmatter 9 Add frontmatter with title, find + download image, add image: field
Total 76

Image Filename Convention

Slugify the .cook filename stem:

  1. Strip .cook extension
  2. Lowercase
  3. Replace runs of non-alphanumeric characters (spaces, punctuation, &, etc.) with a single hyphen
  4. Strip leading/trailing hyphens
  5. Append .webp

Examples:

  • Black Bean and Corn Salad.cookblack-bean-and-corn-salad.webp
  • BUTTERNUT & TURKEY CHILI with sweet peppers, spiced pepitas & queso fresco.cookbutternut-turkey-chili-with-sweet-peppers-spiced-pepitas-queso-fresco.webp
  • Chickpea_Butter_Curry.cookchickpea-butter-curry.webp

Image URL Format

https://roux.roo.lol/recipe-images/<slug>.webp

Image Sourcing

For recipes that already have an image: field

  • Download the image from its current URL (e.g., https://kitchen.roo.lol/data/images/<uuid>.webp)
  • Save locally as <slug>.webp
  • Update the image: field to https://roux.roo.lol/recipe-images/<slug>.webp

For recipes without an image: field

  • Use the recipe title (from frontmatter or content) to search for a relevant, free-to-use food image online
  • Prefer reputable recipe sites, Unsplash/Pexels, or other permissively-licensed sources
  • Download as <slug>.webp
  • Add image: https://roux.roo.lol/recipe-images/<slug>.webp to the frontmatter

For recipes without frontmatter

  • Parse the recipe content to determine a title (from context, first line, or filename)
  • Construct minimal YAML frontmatter: ---, title: <detected title>, ---
  • Find and download image as above
  • Insert frontmatter + image field above the recipe body

Implementation Approach

  1. Batch by category to minimize context switching:

    • Batch 1: 19 existing-image recipes (download + relink)
    • Batch 2: 48 no-image recipes with frontmatter (find + download + add field)
    • Batch 3: 9 no-frontmatter recipes (create frontmatter + find + download + add field)
  2. For image discovery, use a web-search agent to find an appropriate image URL for each recipe, then download via curl.

  3. Parallelize image discovery across multiple subagent workers to keep total time reasonable.

Edge Cases

  • Duplicate-ish recipes (e.g., butternut-turkey-chili.cook, Butternut Turkey Chili.cook, BUTTERNUT & TURKEY CHILI...): Each gets its own image slug. They may share similar images, but each file gets its own entry.
  • Image download failure: If an image URL is unreachable (for existing images) or no suitable image is found (for new ones), log the recipe slug and skip it.
  • Special characters in filenames: Slugify handles &, ', (, ), etc. by collapsing them into hyphens.
  • Existing image URLs that are already in the target format: Skip re-download (they're already correct).
  • Non-WebP source images: Downloaded images should be saved as .webp. If the source is not WebP, use ffmpeg or convert to re-encode.