Compare commits

..

100 Commits

Author SHA1 Message Date
jbrechtel aeebd8a165 converge: auto-commit at 2026-07-13 00:16:49 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 7s
2026-07-12 20:16:49 -04:00
jbrechtel 3bb7fa1bae converge: auto-commit at 2026-07-12 23:00:04 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 15s
2026-07-12 19:00:04 -04:00
jbrechtel 66e7fe4e71 converge: auto-commit at 2026-07-12 22:59:50 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 14s
2026-07-12 18:59:50 -04:00
jbrechtel 563afe82b0 converge: auto-commit at 2026-07-10 02:56:39 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 14s
2026-07-09 22:56:40 -04:00
jbrechtel 3cfd561504 converge: auto-commit at 2026-07-08 22:46:32 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 9s
2026-07-08 18:46:32 -04:00
jbrechtel 652430b42b converge: auto-commit at 2026-07-08 21:44:04 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 13s
2026-07-08 17:44:04 -04:00
jbrechtel 6e0b016f71 converge: auto-commit at 2026-07-08 21:43:48 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 6s
2026-07-08 17:43:49 -04:00
jbrechtel 72478f5871 converge: auto-commit at 2026-07-07 23:07:33 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 15s
2026-07-07 19:07:33 -04:00
jbrechtel 90e4e77248 converge: auto-commit at 2026-07-07 21:55:44 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 11s
2026-07-07 17:55:44 -04:00
jbrechtel 7366a35af5 converge: auto-commit at 2026-07-07 21:55:29 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 1m52s
2026-07-07 17:55:30 -04:00
jbrechtel 9672b857a4 converge: auto-commit at 2026-06-24 23:45:24 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 6s
2026-06-24 19:45:24 -04:00
jbrechtel ba22af10c7 converge: auto-commit at 2026-06-24 23:44:47 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 8s
2026-06-24 19:44:47 -04:00
jbrechtel 6e76daa133 converge: auto-commit at 2026-06-24 23:41:25 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 10s
2026-06-24 19:41:25 -04:00
jbrechtel 260845b2e3 converge: auto-commit at 2026-06-24 23:41:08 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 9s
2026-06-24 19:41:09 -04:00
jbrechtel 42f7839aeb converge: auto-commit at 2026-06-22 21:39:02 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 11s
2026-06-22 17:39:02 -04:00
jbrechtel ecf0cae3ff converge: auto-commit at 2026-06-22 21:38:45 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 11s
2026-06-22 17:38:46 -04:00
jbrechtel 05d1f0f8e5 converge: auto-commit at 2026-06-16 22:53:18 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 9s
2026-06-16 18:53:18 -04:00
jbrechtel 75c799312a converge: auto-commit at 2026-06-16 22:44:00 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 6s
2026-06-16 18:44:00 -04:00
jbrechtel 1cc272795b converge: auto-commit at 2026-06-16 21:55:27 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 9s
2026-06-16 17:55:27 -04:00
jbrechtel 32da5f6762 converge: auto-commit at 2026-06-16 21:55:08 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 11s
2026-06-16 17:55:09 -04:00
jbrechtel e569e3c856 converge: auto-commit at 2026-06-15 22:39:52 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 9s
2026-06-15 18:39:52 -04:00
jbrechtel 3fc17a03ed converge: auto-commit at 2026-06-15 22:39:39 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 7s
2026-06-15 18:39:39 -04:00
jbrechtel a351c289b3 converge: auto-commit at 2026-06-15 22:39:04 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 10s
2026-06-15 18:39:04 -04:00
jbrechtel 1f200d68ef converge: auto-commit at 2026-06-15 22:38:49 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 6s
2026-06-15 18:38:50 -04:00
jbrechtel 644f912a04 converge: auto-commit at 2026-06-14 17:07:06 from pandemic.brechtel
Validate Cooklang / validate (push) Successful in 7s
2026-06-14 13:07:06 -04:00
jbrechtel 202c494fc6 ci: fix cookcli entrypoint — default is 'server', override to 'cook' for doctor validate
Validate Cooklang / validate (push) Successful in 5s
2026-06-02 09:42:51 -04:00
jbrechtel 52f7b34dfc ci: use docker instead of podman for cooklang validation
Validate Cooklang / validate (push) Failing after 13s
2026-06-02 09:39:54 -04:00
jbrechtel 3d8b1e4399 ci: add gitea workflow to validate cooklang files
Validate Cooklang / validate (push) Failing after 5s
2026-06-02 09:36:52 -04:00
jbrechtel 96ca617806 converge: auto-commit at 2026-06-02 13:35:09 from zendo.brechtel
Validate Cooklang / validate (push) Failing after 6s
2026-06-02 09:35:09 -04:00
jbrechtel 7bf748ac37 converge: auto-commit at 2026-05-31 18:49:54 from pandemic.brechtel 2026-05-31 14:49:54 -04:00
jbrechtel f8bfc0c92d converge: auto-commit at 2026-05-31 18:49:34 from pandemic.brechtel 2026-05-31 14:49:34 -04:00
jbrechtel d846802baa converge: auto-commit at 2026-05-31 18:49:23 from pandemic.brechtel 2026-05-31 14:49:23 -04:00
jbrechtel d23afa1a0a converge: auto-commit at 2026-05-31 18:49:07 from pandemic.brechtel 2026-05-31 14:49:07 -04:00
jbrechtel 677b9e355d converge: auto-commit at 2026-05-31 18:43:37 from pandemic.brechtel 2026-05-31 14:43:37 -04:00
jbrechtel eff51a2903 converge: auto-commit at 2026-05-31 18:43:24 from pandemic.brechtel 2026-05-31 14:43:24 -04:00
jbrechtel c67ecacf76 converge: auto-commit at 2026-05-28 11:04:08 from pandemic.brechtel 2026-05-28 07:04:08 -04:00
jbrechtel 1bd068c025 converge: auto-commit at 2026-05-28 11:01:33 from pandemic.brechtel 2026-05-28 07:01:33 -04:00
jbrechtel 67a8ee5ca4 converge: auto-commit at 2026-05-28 11:00:50 from pandemic.brechtel 2026-05-28 07:00:50 -04:00
jbrechtel 864c83ac94 converge: auto-commit at 2026-05-28 11:00:42 from pandemic.brechtel 2026-05-28 07:00:42 -04:00
jbrechtel 82cba01179 converge: auto-commit at 2026-05-28 10:56:45 from pandemic.brechtel 2026-05-28 06:56:45 -04:00
jbrechtel 7a281e47a4 converge: auto-commit at 2026-05-28 10:56:35 from pandemic.brechtel 2026-05-28 06:56:35 -04:00
jbrechtel eea8b16446 converge: auto-commit at 2026-05-28 01:46:22 from pandemic.brechtel 2026-05-27 21:46:22 -04:00
jbrechtel 6daf3bce76 converge: auto-commit at 2026-05-27 23:15:43 from pandemic.brechtel 2026-05-27 19:15:43 -04:00
jbrechtel 3cee695b8d converge: auto-commit at 2026-05-27 21:39:04 from pandemic.brechtel 2026-05-27 17:39:04 -04:00
jbrechtel ce1ecc6e15 converge: auto-commit at 2026-05-27 21:38:19 from pandemic.brechtel 2026-05-27 17:38:19 -04:00
jbrechtel 6da6dea2d0 converge: auto-commit at 2026-05-26 15:24:28 from pandemic.brechtel 2026-05-26 11:24:28 -04:00
jbrechtel 3e01fac842 converge: auto-commit at 2026-05-26 15:24:10 from pandemic.brechtel 2026-05-26 11:24:10 -04:00
jbrechtel 27e5bb921e converge: auto-commit at 2026-05-26 15:23:58 from pandemic.brechtel 2026-05-26 11:23:58 -04:00
jbrechtel 537dcdbc6b converge: auto-commit at 2026-05-26 15:23:47 from pandemic.brechtel 2026-05-26 11:23:47 -04:00
jbrechtel 6cb35647c7 converge: auto-commit at 2026-05-26 15:23:23 from pandemic.brechtel 2026-05-26 11:23:23 -04:00
jbrechtel d3ae6f872f converge: auto-commit at 2026-05-26 15:23:11 from pandemic.brechtel 2026-05-26 11:23:11 -04:00
jbrechtel d0ba79906f converge: auto-commit at 2026-05-26 15:19:48 from pandemic.brechtel 2026-05-26 11:19:48 -04:00
jbrechtel dc8886aee1 converge: auto-commit at 2026-05-26 15:19:25 from zendo.brechtel 2026-05-26 11:19:25 -04:00
jbrechtel e5cecf2dd1 converge: auto-commit at 2026-05-26 15:19:19 from zendo.brechtel 2026-05-26 11:19:19 -04:00
jbrechtel a4f59b9574 converge: auto-commit at 2026-05-26 15:19:07 from zendo.brechtel 2026-05-26 11:19:07 -04:00
jbrechtel ecde8df67f converge: auto-commit at 2026-05-26 15:18:57 from zendo.brechtel 2026-05-26 11:18:57 -04:00
jbrechtel 589b19bb2b converge: auto-commit at 2026-05-26 15:18:02 from zendo.brechtel 2026-05-26 11:18:02 -04:00
jbrechtel 70bf45d719 converge: auto-commit at 2026-05-26 14:15:22 from pandemic.brechtel 2026-05-26 10:15:22 -04:00
jbrechtel b8215d7afe converge: auto-commit at 2026-05-26 13:55:53 from zendo.brechtel 2026-05-26 09:55:53 -04:00
jbrechtel aa6a8f0120 converge: auto-commit at 2026-05-26 13:54:23 from zendo.brechtel 2026-05-26 09:54:23 -04:00
jbrechtel 8050318001 converge: auto-commit at 2026-05-26 13:02:26 from pandemic.brechtel 2026-05-26 09:02:26 -04:00
jbrechtel fd9a9a7755 converge: auto-commit at 2026-05-26 13:02:04 from pandemic.brechtel 2026-05-26 09:02:04 -04:00
jbrechtel e7d20d1619 converge: auto-commit at 2026-05-26 13:00:06 from pandemic.brechtel 2026-05-26 09:00:06 -04:00
jbrechtel 35131584ea converge: auto-commit at 2026-05-26 12:56:25 from pandemic.brechtel 2026-05-26 08:56:25 -04:00
jbrechtel cbd7dca04c converge: auto-commit at 2026-05-26 10:56:54 from zendo.brechtel 2026-05-26 06:56:54 -04:00
jbrechtel 28ab94f60b converge: auto-commit at 2026-05-26 10:42:09 from zendo.brechtel 2026-05-26 06:42:09 -04:00
jbrechtel 62e52349cb converge: auto-commit at 2026-05-26 10:37:10 from pandemic.brechtel 2026-05-26 06:37:10 -04:00
jbrechtel 2f13195a48 converge: auto-commit at 2026-05-26 02:12:20 from zendo.brechtel 2026-05-25 22:12:20 -04:00
jbrechtel 5f8610bfe2 converge: auto-commit at 2026-05-26 01:55:15 from pandemic.brechtel 2026-05-25 21:55:15 -04:00
jbrechtel 9e7d78ccb2 converge: auto-commit at 2026-05-26 00:07:34 from pandemic.brechtel 2026-05-25 20:07:34 -04:00
jbrechtel cb9c0c5e0d converge: auto-commit at 2026-05-26 00:07:14 from pandemic.brechtel 2026-05-25 20:07:14 -04:00
jbrechtel 1278f9fe42 converge: auto-commit at 2026-05-26 00:06:42 from pandemic.brechtel 2026-05-25 20:06:42 -04:00
jbrechtel 8665b25c16 converge: auto-commit at 2026-05-22 01:57:32 from zendo.brechtel 2026-05-21 21:57:32 -04:00
jbrechtel 56e2f38da7 converge: auto-commit at 2026-05-22 01:57:23 from zendo.brechtel 2026-05-21 21:57:23 -04:00
jbrechtel 7597179651 converge: auto-commit at 2026-05-22 01:55:43 from pandemic.brechtel 2026-05-21 21:55:43 -04:00
jbrechtel 27fc455b9f converge: auto-commit at 2026-05-22 01:55:30 from pandemic.brechtel 2026-05-21 21:55:30 -04:00
jbrechtel 69fa7be9e8 converge: auto-commit at 2026-05-22 01:54:46 from zendo.brechtel 2026-05-21 21:54:46 -04:00
jbrechtel 888a9f7afa converge: auto-commit at 2026-05-22 01:54:38 from zendo.brechtel 2026-05-21 21:54:38 -04:00
jbrechtel 504779ce21 converge: auto-commit at 2026-05-22 01:49:04 from pandemic.brechtel 2026-05-21 21:49:04 -04:00
jbrechtel 54f567457a converge: auto-commit at 2026-05-22 01:09:57 from pandemic.brechtel 2026-05-21 21:09:57 -04:00
jbrechtel 91a9c6ad24 converge: auto-commit at 2026-05-22 01:09:07 from pandemic.brechtel 2026-05-21 21:09:07 -04:00
jbrechtel 11047b6349 converge: auto-commit at 2026-05-22 00:49:16 from pandemic.brechtel 2026-05-21 20:49:16 -04:00
jbrechtel 042c10ace4 converge: auto-commit at 2026-05-21 22:59:44 from zendo.brechtel 2026-05-21 18:59:44 -04:00
jbrechtel 51101cbd57 converge: auto-commit at 2026-05-21 22:59:33 from zendo.brechtel 2026-05-21 18:59:33 -04:00
jbrechtel f31e668dee converge: auto-commit at 2026-05-21 22:59:10 from zendo.brechtel 2026-05-21 18:59:10 -04:00
jbrechtel 61c5185d81 converge: auto-commit at 2026-05-21 22:58:42 from zendo.brechtel 2026-05-21 18:58:42 -04:00
jbrechtel 2c46d28956 converge: auto-commit at 2026-05-21 22:58:26 from zendo.brechtel 2026-05-21 18:58:26 -04:00
jbrechtel d7a1829592 converge: auto-commit at 2026-05-21 22:31:47 from pandemic.brechtel 2026-05-21 18:31:47 -04:00
jbrechtel 80307afdbc converge: auto-commit at 2026-05-21 22:31:33 from pandemic.brechtel 2026-05-21 18:31:33 -04:00
jbrechtel ed8e75295e converge: auto-commit at 2026-05-21 20:59:39 from pandemic.brechtel 2026-05-21 16:59:39 -04:00
jbrechtel 6d2b07b1b5 converge: auto-commit at 2026-05-21 20:59:24 from pandemic.brechtel 2026-05-21 16:59:24 -04:00
jbrechtel 75e1fab8d4 merge: feature/recipe-images into main
Add image metadata to all 78 .cook recipe files:
- Download and relink 19 existing images to roux.roo.lol
- Find and download images for 50 recipes with frontmatter
- Add frontmatter and images for 9 recipes without frontmatter
- All images converted to proper WebP format
2026-05-21 15:05:58 -04:00
jbrechtel 61963e72f5 fix: correct YAML frontmatter, convert images to proper WebP format
- Moved image: field from outside to inside YAML frontmatter (50 files)
- Converted all 56 non-WebP images to proper WebP format via ImageMagick
- Fixed Python shebangs for portability
- Updated source fields in 2 Task 3 recipes
2026-05-21 15:03:13 -04:00
jbrechtel c864c670b7 chore: cleanup temp files after recipe image ingestion 2026-05-21 14:59:25 -04:00
jbrechtel a256c14932 feat: add frontmatter and images to 9 recipes without frontmatter (Task 3) 2026-05-21 14:59:03 -04:00
jbrechtel ed70f6e3c2 feat: add images to all 50 recipes with frontmatter (Task 2)
Downloaded recipe images from source URLs (NYT Cooking, Love & Lemons,
Food Network, etc.) via og:image scraping and DuckDuckGo search + page
scraping for recipes without direct source URLs.
2026-05-21 14:58:14 -04:00
jbrechtel 94775414bd feat: download and relink existing recipe images to roux.roo.lol 2026-05-21 14:46:04 -04:00
jbrechtel 36d4fc205e fix: deduplicate slugs, update plan to reflect actual count of 50 (not 48) 2026-05-21 14:45:00 -04:00
jbrechtel 428f819f9c chore: add recipe slug mapping and classification CSVs 2026-05-21 14:42:49 -04:00
jbrechtel bd7278569e chore: add .gitignore and docs/specs/2026-05-21-recipe-images-design.md 2026-05-21 14:41:42 -04:00
224 changed files with 4002 additions and 272 deletions
+23
View File
@@ -0,0 +1,23 @@
# Validates that all .cook files in this repository are valid Cooklang recipes.
# Uses cookcli (https://hub.docker.com/r/inigochoa/cookcli) via Docker.
name: Validate Cooklang
on:
push:
pull_request:
branches: [main, master]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate all .cook files
run: |
docker run --rm \
--entrypoint cook \
-v "$(pwd):/recipes:ro" \
docker.io/inigochoa/cookcli \
doctor validate -b /recipes --strict
+4 -8
View File
@@ -4,18 +4,14 @@ title: Alain Ducasse's Gougères
servings: 28
category: Bread
category: appetizer
source: https://www.foodandwine.com/recipes/alain-ducasses-gougeres
description: "Alain Ducasse's recipe for gougères. These airy French cheese puffs, flavored with Gruyère cheese and a hint of nutmeg, make phenomenal hors d'oeuvres."
tags:
- bread
- vegetarian
- french
- cheese
image: https://roux.roo.lol/recipe-images/alain-ducase-bread.webp
---
+6 -1
View File
@@ -2,8 +2,13 @@
title: Apple Cider Vinegar Dressing
description: This homemade apple cider vinaigrette is SO much better than any store bought dressing! Made with 7 simple ingredients, it's tangy, healthy, and easy to make.
servings: 6
category: salad
tags:
- vegetarian
- vegan
- gluten-free
source: https://www.loveandlemons.com/apple-cider-vinegar-dressing/
image: https://kitchen.roo.lol/data/images/14663763-8d52-4e31-a4e8-36a7f3c6c229.webp
image: https://roux.roo.lol/recipe-images/apple-cider-vinegar-dressing.webp
thumbnail: https://kitchen.roo.lol/data/images/thumbnails/14663763-8d52-4e31-a4e8-36a7f3c6c229.webp
date_created: 2024-11-03
date_modified: 2024-11-03
@@ -8,18 +8,13 @@ prep_time: 25 minutes
time: 25 minutes
category: main course
category: dinner
tags:
- meat
- chicken
- garnish-and-gather
- orzo
- pesto
- pasta
image: https://roux.roo.lol/recipe-images/arugula-pesto-chicken-with-pecans-roasted-butternut.webp
---
+4 -4
View File
@@ -1,13 +1,13 @@
---
title: Arugula Pesto Wheat Berries Recipe
servings: 1
category: uncategorized
category: lunch
source: https://www.101cookbooks.com/archives/arugula-pesto-wheat-berries-recipe.html
description: "A peppery arugula pesto tossed with a bowl of plump, chewy wheat berries."
tags:
- arugula
- pesto
- wheat berries
- vegetarian
- grain-bowl
image: https://roux.roo.lol/recipe-images/arugula-pesto-wheat-berries-recipe.webp
---
Place the @cooked wheat berries{3%cups} in a large mixing bowl and set them aside so they can come up to room temperature if you've had them in the refrigerator.
+2 -2
View File
@@ -2,14 +2,14 @@
title: Asparagus Salad
prep_time: 20 minutes
cook_time: 5 minutes
category: Salad
category: salad
tags:
- vegetarian
- gluten-free
- spring
- salad
description: A fresh spring asparagus salad with peas, radishes, feta, pine nuts, and herbs, tossed with lemon and olive oil and finished with creamy avocado dressing.
source: Love and Lemons
image: https://roux.roo.lol/recipe-images/asparagus-salad.webp
---
Bring a large #pot of well-salted @water{} to a boil and prepare a #bowl of @ice water{}.
+4 -3
View File
@@ -1,13 +1,14 @@
---
title: Authentic Cacio e Pepe Recipe
servings: 2
category: uncategorized
category: dinner
description: "A cacio e pepe is so simple, the whole recipe is 3 ingredients: pecorino romano, black pepper and pasta."
source: https://pinabresciani.com/authentic-cacio-e-pepe-recipe/
tags:
- pasta
- vegetarian
- italian
- quick
- pasta
image: https://roux.roo.lol/recipe-images/authentic-cacio-e-pepe-recipe.webp
---
In a #pot, bring @water{} to a boil. Lightly salt the water when it comes to a boil.
@@ -1,34 +0,0 @@
---
title: BUTTERNUT & TURKEY CHILI with sweet peppers, spiced pepitas & queso fresco
servings: 1
prep_time: 20 minutes
time: 1 hour
category: mains
description: "A hearty chili made with ground turkey, butternut squash, and sweet peppers, topped with spiced pepitas and queso fresco."
tags:
- butternut squash
- chili
- turkey
---
Heat ~{1%Tbsp} @olive oil{} in a #pot over medium heat.
Add @pepitas{1/4%cups}, pepita spice (¼%tsp smoked paprika, ⅛%tsp cayenne, ⅛%tsp cinnamon) and a pinch of @salt{}. Toast, stirring frequently, until fragrant and lightly browned, about ~{3-5%minutes}, then remove and set aside.
Chop @sweet pepper{3/4%cup} and @cilantro{}; drain and rinse @beans{}; cut @lime{} into wedges.
In the same #pot, heat ~{2%Tbsp} @olive oil over medium-high.
Add @ground turkey{8%oz} and ~{1/4%tsp} each @salt{} & @pepper{}, cook ~{5-8%minutes} until browned, breaking up; remove and set aside.
Add @butternut squash{1.5%cups} and @onion{2%tbsp}(chopped) to the pot and cook until beginning to soften, ~{5-7%minutes}.
Add Chili Spice (1%Tbsp chili powder, 2%tsp cumin, 1%tsp smoked paprika, 1/2%tsp dried oregano) and cook ~{1%minute} until fragrant.
Stir in @tomatoes{}, @broth{}, @water{1/2%cup}, cooked turkey, @beans{} and ~{1/2%tsp} @salt{}. Bring to a boil, reduce heat to low and simmer until butternut is tender, about ~{20%minutes}.
Crumble @queso fresco{}.
Adjust seasoning to taste.
Serve chili in bowls topped with spiced @pepitas{}, sour cream (optional), queso fresco, cilantro & lime wedges.
+4 -3
View File
@@ -3,12 +3,13 @@ title: Baked Chile Relleno with Black Beans
servings: 2
prep_time: 25 minutes
time: 25 minutes
category: main course
category: dinner
description: "Roasted poblano peppers stuffed with a black bean and Monterey Jack filling, baked with ranchero sauce."
tags:
- mexican
- peppers
- vegetarian
- mexican
- beans
image: https://roux.roo.lol/recipe-images/baked-chile-relleno-with-black-beans.webp
---
Preheat the #oven to high broil with a rack near the broiler.
+5 -4
View File
@@ -2,14 +2,15 @@
title: Bang Bang Tofu
servings: 2
prep_time: 20 minutes
category: main course
category: dinner
cuisine: Asian Fusion
description: Crispy fried tofu with spicy bang bang sauce served over scallion rice with snow peas
tags:
- asian fusion
- rice
- tofu
- vegetarian
- vegan-option
- asian
- tofu
image: https://roux.roo.lol/recipe-images/bang-bang-tofu.webp
---
Drain @tofu{1%lb}, pat dry, and place on a plate lined with several paper towels or a clean dish towel to dry for ~{15%minutes}.
@@ -3,12 +3,12 @@ title: Barbecue Chicken with Crispy Pan-Fried Okra & Cheddar Biscuits
servings: 2
prep_time: 20 minutes
time: 20 minutes
category: main course
category: dinner
tags:
- bbq
- meat
- chicken
- biscuits
- okra
- southern
image: https://roux.roo.lol/recipe-images/barbecue-chicken-with-crispy-pan-fried-okra-cheddar-biscuits.webp
---
Preheat the #oven to 400°F and lightly grease a #baking sheet.
+5 -6
View File
@@ -6,12 +6,11 @@ category: salad
source: https://www.loveandlemons.com/black-bean-and-corn-salad/
description: "This black bean and corn salad is a delicious summer side dish or healthy lunch! It keeps well for up to 3 days in the fridge, but if you're making it in advance, wait to add the avocado until right before you eat. Otherwise, it will start to brown."
tags:
- black beans
- corn
- salad
- avocado
- summer
- healthy
- vegetarian
- vegan
- gluten-free
- mexican
image: https://roux.roo.lol/recipe-images/black-bean-and-corn-salad.webp
---
In a large #mixing bowl{}, whisk together the @lime juice{1/4%cup}, @avocado oil{3%tablespoons}, @garlic{1%clove}, grated, @cumin{1/2%teaspoon}, @sea salt{3/4%teaspoon}, and @black pepper{}.
+14
View File
@@ -1,3 +1,17 @@
---
title: Black Pepper Tofu (Ottolenghi)
description:
servings: 1
category: dinner
source: Unknown
image: https://roux.roo.lol/recipe-images/black-pepper-tofu-ottolenghi.webp
tags:
- vegetarian
- asian
- tofu
- vegan-option
---
>> Servings: 4
Pour enough @vegetable oil{} into a large #frying pan or wok{} to come 1/4 inch and turn on heat.
+14
View File
@@ -1,3 +1,17 @@
---
title: Black Pepper Tofu with Bok Choy
description:
servings: 1
category: dinner
source: Unknown
image: https://roux.roo.lol/recipe-images/black-pepper-tofu-with-bok-choy.webp
tags:
- vegetarian
- asian
- tofu
- vegan-option
---
>> Servings: 2
>> Prep time: 30 minutes
>> Total time: 30 minutes
+6 -2
View File
@@ -1,12 +1,16 @@
---
title: Blackened Shrimp & Gouda Grits
servings: 2
category: main course
category: dinner
cuisine: Southern
tags: caesar salad,garnish-and-gather,seafood,shrimp and grits,southern
tags:
- seafood
- shrimp
- southern
source: Unknown
description: Southern-style shrimp and grits with smoked gouda, served with a charred scallion kale caesar salad
prep_time: 25 minutes
image: https://roux.roo.lol/recipe-images/blackened-shrimp-and-gouda-grits.webp
---
In a #pot{}, bring 3 cups @water{} & @salt{1/2 teaspoon} to a boil.
+6 -2
View File
@@ -1,10 +1,14 @@
---
title: Tofu Makhani (Indian Butter Tofu)
servings: 6
category: uncategorized
category: dinner
source: https://cooking.nytimes.com/recipes/1020094-tofu-makhani-indian-butter-tofu
description: This recipe is a vegetarian riff on butter chicken, or murgh makhani, a classic Indian dish in which chicken simmers in a rich, dairy-laden tomato sauce that's seasoned with heady spices like turmeric, cumin, garam masala and cardamom. This weeknight-friendly version has a toned-down ingredient list, and the tofu doesn't require hours of marinating, which means you can get everything on the table in under an hour if you start the rice as the tomatoes are cooking down. Heavy cream gives this dish a rich finish, but full-fat coconut milk makes a fine substitute. Whatever you do, don't substitute anything for butter or ghee (sorry, vegans) — it's signature ingredient.
image: https://kitchen.roo.lol/data/images/99596aa7-0678-40ce-8020-f2ae9308be6a.webp
image: https://roux.roo.lol/recipe-images/butter-tofu.webp
tags:
- vegetarian
- indian
- tofu
---
In a large #bowl{}, whisk @fresh lemon juice{2 tablespoons}, @ground cumin{1 tablespoon} and 1 heaping tablespoon @ground turmeric{} with 1 tablespoon @water{} to make a thin paste. Drain and pat @tofu{2 (14-ounce) packages, firm} dry then cut it into 1-inch cubes. Add @tofu{} to the @turmeric{} marinade, gently stirring to coat. Set aside at room temperature while you prepare the remaining ingredients, or cover and refrigerate for up to 1 day.
-34
View File
@@ -1,34 +0,0 @@
---
title: Butternut and Turkey Chili
servings: 1
prep_time: 20 minutes
time: 1 hour
category: mains
description: "A hearty chili made with ground turkey, butternut squash, and sweet peppers, topped with spiced pepitas and queso fresco."
tags:
- butternut squash
- chili
- turkey
---
Heat ~{1%Tbsp} @olive oil{} in a #pot over medium heat.
Add @pepitas{1/4%cups}, pepita spice (¼%tsp smoked paprika, ⅛%tsp cayenne, ⅛%tsp cinnamon) and a pinch of @salt{}. Toast, stirring frequently, until fragrant and lightly browned, about ~{3-5%minutes}, then remove and set aside.
Chop @sweet pepper{3/4%cup} and @cilantro{}; drain and rinse @beans{}; cut @lime{} into wedges.
In the same #pot, heat ~{2%Tbsp} @olive oil over medium-high.
Add @ground turkey{8%oz} and ~{1/4%tsp} each @salt{} & @pepper{}, cook ~{5-8%minutes} until browned, breaking up; remove and set aside.
Add @butternut squash{1.5%cups} and @onion{2%tbsp}(chopped) to the pot and cook until beginning to soften, ~{5-7%minutes}.
Add Chili Spice (1%Tbsp chili powder, 2%tsp cumin, 1%tsp smoked paprika, 1/2%tsp dried oregano) and cook ~{1%minute} until fragrant.
Stir in @tomatoes{}, @broth{}, @water{1/2%cup}, cooked turkey, @beans{} and ~{1/2%tsp} @salt{}. Bring to a boil, reduce heat to low and simmer until butternut is tender, about ~{20%minutes}.
Crumble @queso fresco{}.
Adjust seasoning to taste.
Serve chili in bowls topped with spiced @pepitas{}, sour cream (optional), queso fresco, cilantro & lime wedges.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Cabbage Salad
servings: 6
category: Salad
category: salad
source: https://www.loveandlemons.com/cabbage-salad/
image: https://roux.roo.lol/recipe-images/cabbage-salad.webp
tags:
- vegetarian
- vegan
- gluten-free
---
In a large bowl, toss together @green cabbage{4%cup}, @red cabbage{4%cup}, @red bell pepper{1%medium}, @carrots{1%cup}(julienned), @cilantro{1/2%cup}(chopped).
@@ -1,10 +1,15 @@
---
title: Cajun Shrimp and Sausage Vegetable Foil Packets
servings: 4
category: uncategorized
category: dinner
source: https://therecipecritic.com/cajun-shrimp-and-sausage-vegetable-foil-packets/
description: Cajun Shrimp and Sausage Foil Packets are loaded with shrimp, sausage, summer vegetables and tossed in cajun spices. These are quick and easy and packed with big flavor!
image: https://kitchen.roo.lol/data/images/9f6c7d9f-c6d7-4ea3-bad7-dcffe1187cba.webp
image: https://roux.roo.lol/recipe-images/cajun-shrimp-and-sausage-vegetable-foil-packets.webp
tags:
- seafood
- shrimp
- cajun
- sausage
---
In a large #bowl{} add @shrimp{1 pound, large, peeled and deveined}, @sausage{14 ounce, pork or chicken, sliced}, @zucchini{2 medium sized, sliced}, @yellow squash{2 medium sized, sliced}, @asparagus{½ bunch, sliced into thirds}, @red bell pepper{2, chopped into chunks} and @salt{} and @pepper{}. Add @olive oil{3 Tablespoons} and @cajun seasoning{3 Tablespoons} and toss until coated.
@@ -3,11 +3,15 @@ title: Cajun Spice Mix (for pecans, oysters, etc)
description: A Leonard-family recipe for spice mix for seasoning Cajun Pecans or Oysters
servings: 9
source: Mealie
image: https://kitchen.roo.lol/data/images/c0540c17-29a5-4fe3-b038-1b421037c6e8.webp
image: https://roux.roo.lol/recipe-images/cajun-spice-mix-for-pecans-oysters-etc.webp
thumbnail: https://kitchen.roo.lol/data/images/thumbnails/c0540c17-29a5-4fe3-b038-1b421037c6e8.webp
date_created: 2024-11-03
date_modified: 2024-11-03
date_published: 2024-11-03
tags:
- vegetarian
- vegan
- spice-blend
---
= Spice Mix =
+12
View File
@@ -1,3 +1,15 @@
---
title: Caramel Cake
description:
servings: 1
category: lunch
source: Unknown
image: https://roux.roo.lol/recipe-images/caramel-cake.webp
tags:
- vegetarian
- dessert
---
>> Servings: 10
Combine @sour cream{8 ounces} and @milk{1/4 cup}.
+12
View File
@@ -1,3 +1,15 @@
---
title: Caramel Icing
description:
servings: 1
category: lunch
source: Unknown
image: https://roux.roo.lol/recipe-images/caramel-icing.webp
tags:
- vegetarian
- dessert
---
>> Servings: 10
Sprinkle @sugar{1/2 cup} in a shallow heavy #3½-quart Dutch oven{}.
+7 -2
View File
@@ -4,9 +4,14 @@ description: I think my mom lied to me about this chana salaad. She said it was
prep_time: 10 minutes
cook_time: 30 minutes
servings: 6
category: side
category: salad
source: OCR
tags: salad, indian, vegan, gluten-free, instant-pot, chickpea
tags:
- vegetarian
- vegan
- indian
- gluten-free
image: https://roux.roo.lol/recipe-images/chana-chickpea-salad.webp
---
In the inner cooking pot of the #Instant Pot, combine the @chickpea{1%can}, @bay leaf{2}, and @water{4%cups}.
+7 -2
View File
@@ -1,10 +1,15 @@
---
title: Chana Salad
servings: 6
category: side
category: salad
source: OCR
description: I think my mom lied to me about this chana salaad. She said it was junk food so I would eat it, but now that I'm older I know better. After all, it's chickpeas and vegetables! But I'm glad my mom said whatever it took at time to get me to eat it, because I love this salad. It is perfect for summer and is easy to make. Serve it as a side salad or as a main dish for a vegan meal. Adjust cayenne as desired for your heat preference. SERVES 6
image: https://kitchen.roo.lol/data/images/bd956abd-bbc8-4b7c-87e1-8c7ca70f804d.webp
image: https://roux.roo.lol/recipe-images/chana-salad.webp
tags:
- vegetarian
- vegan
- indian
- gluten-free
---
In inner cooking pot of #InstantPot, combine @chickpeas{1 can, 15-16 ounces}, @bay leaves{}, and @water{}.
@@ -1,12 +1,17 @@
---
title: Chicken & Pumpkin Gnocchi with Ricotta
servings: 2
category: main course
tags: garnish-and-gather,gnocchi,italian,pumpkin
category: dinner
tags:
- meat
- chicken
- pasta
- fall
source: garnish-and-gather
description:
prep_time: 35 minutesnutes
totalTime: PT35M
image: https://roux.roo.lol/recipe-images/chicken-and-pumpkin-gnocchi-with-ricotta.webp
---
Remove any large stems from @spinach{2 1/2 cups} and roughly chop.
+7 -2
View File
@@ -1,13 +1,18 @@
---
title: Chickpea Butter Curry
servings: 2
category: main course
category: dinner
cuisine: Indian
tags: chickpeas,curry,garnish-and-gather,indian,vegetarian
tags:
- vegetarian
- indian
- curry
- vegan-option
source: Unknown
description: A vegetarian curry with chickpeas, cauliflower, and coconut milk, served with spiced oil drizzle
prep_time: 20 minutes
cook_time: 20 minutes
image: https://roux.roo.lol/recipe-images/chickpea-butter-curry.webp
---
In a small #pot{}, bring 1 1/2 cups @water{} & @basmati rice{3/4 cup} to a boil, then cover, reduce heat to low, and cook ~{12-15 minutes} or until @rice{} is tender.
+7 -1
View File
@@ -1,8 +1,14 @@
---
title: Chickpea Butter Curry
servings: 2
category: Main
category: dinner
source: Rebel Recipes
image: https://roux.roo.lol/recipe-images/chickpea-butter-curry-2.webp
tags:
- vegetarian
- indian
- curry
- vegan-option
---
In a small pot, bring 1 1/2 cups water and @basmati rice{3/4%cup} to a boil, then cover, reduce heat to low, and cook 12-15 minutes or until rice is tender.
+6 -2
View File
@@ -1,13 +1,17 @@
---
title: Chinese Orange Shrimp
servings: 2
category: main course
category: dinner
cuisine: Chinese
tags: chinese,garnish-and-gather,orange sauce,shrimp,stir-fry
tags:
- seafood
- shrimp
- asian
source: Unknown
description: Shrimp in orange sauce with brussels sprouts and carrots served over scallion rice
prep_time: 15 minutes
cook_time: 15 minutes
image: https://roux.roo.lol/recipe-images/chinese-orange-shrimp.webp
---
In a #pot{}, bring 1 1/2 cups @water{} & @salt{1/4 teaspoon} to a boil.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Chocolate Mousse Cake with Raspberries
servings: 24
category: Desserts
category: lunch
source: King Arthur Baking
image: https://roux.roo.lol/recipe-images/chocolate-mousse-cake-with-raspberries.webp
tags:
- vegetarian
- dessert
- chocolate
---
Preheat the oven to 325°F. Lightly grease two 8" round pans (or adjust for your pan mix) and line with parchment.
+6 -2
View File
@@ -1,12 +1,16 @@
---
title: Cilantro Pesto Shrimp Over Orzo
servings: 2
category: main course
tags: garnish-and-gather,mediterranean,orzo,pesto,shrimp
category: dinner
tags:
- seafood
- shrimp
- pasta
source: Unknown
description:
prep_time: 20 minutes
totalTime: PT20M
image: https://roux.roo.lol/recipe-images/cilantro-pesto-shrimp-over-orzo.webp
---
Juice HALF of @lemon{1} and cut remainder into wedges.
@@ -1,8 +1,14 @@
---
title: Crispy Roasted Chickpeas (Garbanzo Beans)
servings: 2
category: Snack
category: appetizer
source: Unknown
image: https://roux.roo.lol/recipe-images/crispy-roasted-chickpeas-garbanzo-beans.webp
tags:
- vegetarian
- vegan
- gluten-free
- snack
---
Preheat the oven to 400°F.
@@ -1,10 +1,15 @@
---
title: Crispy Tofu With Cashews and Blistered Snap Peas
servings: 4
category: uncategorized
category: dinner
source: https://cooking.nytimes.com/recipes/1021200-crispy-tofu-with-cashews-and-blistered-snap-peas?campaign_id=9&emc=edit_nn_20230415&instance_id=90280&nl=the-morning&regi_id=123169868&segment_id=130511&te=1&user_id=c5863897ec3230a42bc044f493123ca2
description: A ginger and coconut milk reduction can coat pretty much anything that browns nicely on its own. Here, it's pieces of pan-seared tofu, but small morsels of chicken and pork will work just as well. The soy and teaspoons of molasses give sauce a little caramelization, and a little shine and gloss. For a fresh side, add some blistered snap peas, tossed with sliced scallions, a little mint and a splash of rice vinegar. Snow peas, green beans, broccoli or asparagus? If it's fresh and green, it'll work just fine.
image: https://kitchen.roo.lol/data/images/9fe7eb34-2b1c-4dba-88e8-eb4ba4abea8e.webp
image: https://roux.roo.lol/recipe-images/crispy-tofu-with-cashews-and-blistered-snap-peas.webp
tags:
- vegetarian
- asian
- tofu
- vegan-option
---
Slice @tofu{1 (14-ounce) block, firm or extra-firm, drained} in half horizontally, and leave on #paper towels{} to dry any excess liquid.
@@ -1,8 +1,14 @@
---
title: Crispy Roasted Chickpeas (Garbanzo Beans)
servings: 2
category: Snack
category: appetizer
source: Unknown
image: https://roux.roo.lol/recipe-images/crispy-roasted-chickpeas-garbanzo-beans-2.webp
tags:
- vegetarian
- vegan
- gluten-free
- snack
---
Preheat the oven to 400°F.
+4 -4
View File
@@ -2,15 +2,15 @@
title: Dried Fava Soup with Mint and Guajillo Chiles
prep_time: 10 minutes
cook_time: 100 minutes
category: Soup
category: lunch
tags:
- vegetarian
- vegan-optional
- mexican-inspired
- beans
- vegan
- soup
- mexican
description: A slow-simmered dried fava bean soup with roasted tomatoes, garlic, and onion, finished with mint and cilantro and topped with a tangy quick-pickled guajillo chile mixture.
source: 101 Cookbooks (adapted from Rick Baylesss Mexican Kitchen)
image: https://roux.roo.lol/recipe-images/dried-fava-soup.webp
---
Make sure the @hulled dried fava bean{1%lb} are clean and free of dirt, then rinse them well.
+7 -1
View File
@@ -1,8 +1,14 @@
---
title: EASY LEMON ROSEMARY WHITE BEAN SOUP
servings: 4
category: Soup
category: lunch
source: Simple Veganista
image: https://roux.roo.lol/recipe-images/easy-lemon-rosemary-white-bean-soup.webp
tags:
- vegetarian
- vegan
- soup
- gluten-free
---
Saute @olive oil{2%tbsp} in a large pot. Add @onion{1%small}, @carrots{3%large} and @celery{2 stalks}; cook for 7 minutes until softened.
+7 -2
View File
@@ -1,10 +1,15 @@
---
title: Easy Vegetarian Chili
servings: 6
category: uncategorized
category: dinner
source: https://www.loveandlemons.com/vegetarian-chili-recipe/
description: You'll LOVE this easy vegetarian chili recipe! It's gluten-free, and without yogurt or sour cream on top, it's also vegan.
image: https://kitchen.roo.lol/data/images/61187b69-c326-4ad4-aa03-f3eb7c0b1806.webp
image: https://roux.roo.lol/recipe-images/easy-vegetarian-chili.webp
tags:
- vegetarian
- vegan
- chili
- soup
---
Heat @extra-virgin olive oil{2 tablespoons} in a large #pot{} over medium heat. Add @yellow onion{1 small, chopped}, a few pinches of @salt{} and @pepper{}, and stir. Cook until @onion{} is translucent, ~{5 minutes}, then add @garlic{2 cloves, minced} and @red bell pepper{1, diced}. Stir and cook until soft, ~{5 to 8 minutes}, turning heat down as needed.
+7 -1
View File
@@ -1,8 +1,14 @@
---
title: EASY LEMON ROSEMARY WHITE BEAN SOUP
servings: 4
category: Soup
category: lunch
source: Simple Veganista
image: https://roux.roo.lol/recipe-images/easy-lemon-rosemary-white-bean-soup-2.webp
tags:
- vegetarian
- vegan
- soup
- gluten-free
---
Saute @olive oil{2%tbsp} in a large pot. Add @onion{1%small}, @carrots{3%large} and @celery{2 stalks}; cook for 7 minutes until softened.
@@ -1,14 +1,18 @@
---
title: Fettucine with spiced cherry tomato sauce
servings: 4
category: uncategorized
category: dinner
source: Mealie
description: This is basically spaghetti with a sauce made from scratch. The sauce is great and I think this whole recipe is really good especially considering the ingredients are so basic.
I added red pepper to the recipe for extra kick.
image: https://kitchen.roo.lol/data/images/1a3fbf92-6d4b-4f74-adf3-0b004b5f021a.webp
image: https://roux.roo.lol/recipe-images/fettucine-with-spiced-cherry-tomato-sauce.webp
prep_time: 30 minutes
cook_time: 1 hour
tags:
- vegetarian
- italian
- pasta
---
Heat @olive oil{5tbsp} in a large #saute pan{} on medium-high heat.
+6 -2
View File
@@ -1,11 +1,15 @@
---
title: Gaja's Bulgogi Lettuce Wraps
servings: 2
category: main course
tags: bulgogi,garnish-and-gather,korean,lettuce wraps
category: dinner
tags:
- meat
- asian
- korean
source: Unknown
description:
prep_time: 20 minutes
image: https://roux.roo.lol/recipe-images/gaja-s-bulgogi-lettuce-wraps.webp
---
Pat @steak bulgogi{8 oz} dry.
+7 -2
View File
@@ -1,12 +1,17 @@
---
title: Gochugaru Honey Salmon
servings: 2
category: main course
category: dinner
cuisine: Korean Fusion
tags: crispy rice,garnish-and-gather,gochugaru,korean,salmon
tags:
- seafood
- salmon
- asian
- korean
source: Unknown
description: Salmon with spicy honey sauce served with crispy rice, broccoli, and carrots
prep_time: 25 minutes
image: https://roux.roo.lol/recipe-images/gochugaru-honey-salmon.webp
---
In a #pot{}, bring 1 1/2 cups @water{} to a boil for @rice{3/4 cup, long grain}.
+7 -2
View File
@@ -1,10 +1,10 @@
---
title: Green Beans with Lemon and Garlic
servings: 6
category: Thanksgiving
category: lunch
source: https://www.foodnetwork.com/recipes/patrick-and-gina-neely/green-beans-with-lemon-and-garlic-recipe-1938670
description: The Neelys' healthy Green Beans with Lemon and Garlic recipe from Food Network is the perfect, simple side for any occasion. Quickly blanch and finish on the skillet, these green beans will be on the table in less than 20 minutes.
image: https://kitchen.roo.lol/data/images/704b15f5-0eda-4f7f-8762-1d8f36c2dea6.webp
image: https://roux.roo.lol/recipe-images/green-beans-with-lemon-and-garlic.webp
nutrition:
calories: 122 kcal
carbohydrate: 11g
@@ -13,6 +13,11 @@ nutrition:
protein: 3g
sodium: 126mg
sugar: 5g
tags:
- vegetarian
- vegan
- gluten-free
- side
---
Blanch @green beans{2%pounds}(ends trimmed) in a large #stock pot{} of well salted boiling water until bright green in color and tender crisp, roughly ~{2%minutes}. Drain and shock in a #bowl{} of ice water to stop from cooking.
+6 -2
View File
@@ -1,12 +1,16 @@
---
title: Indian Spiced Chicken with Creamy Tomato Sauce & Spinach
servings: 2
category: main course
tags: basmati rice,chicken,curry,garnish-and-gather,indian
category: dinner
tags:
- meat
- chicken
- indian
source: Unknown
description:
prep_time: 20 minutes
cook_time: 20 minutes
image: https://roux.roo.lol/recipe-images/indian-spiced-chicken-2.webp
---
Bring 1 1/2 cups @water{} & @salt{1/4 tsp} to a boil in a #pot{}.
@@ -1,3 +1,17 @@
---
title: Italian Sausage & Delicata Rigatoni
description:
servings: 1
category: dinner
source: Unknown
image: https://roux.roo.lol/recipe-images/italian-sausage-and-delicata-rigatoni.webp
tags:
- meat
- sausage
- pasta
- italian
---
>> title: Italian Sausage & Delicata Rigatoni
>> author: Chef Robin Pridgen
>> servings: 2
+7 -2
View File
@@ -1,13 +1,18 @@
---
title: Kale & Chestnut Stew with Butternut Squash, Wild Rice & ParsleyWalnut Pesto
servings: 2
category: main dish
category: dinner
cuisine: American
tags: stew,kale,butternut-squash,wild-rice,parsley,walnut,pesto,dairy,garnish-and-gather
tags:
- vegetarian
- vegan-option
- soup
- fall
source: Garnish & Gather — Chef Emily Golub
description: Cozy kale-and-chestnut stew finished with cream and topped with a bright parsleywalnut pesto. Allergens: dairy, walnuts.
prep_time: 20 minutes
cook_time: 35 minutes
image: https://roux.roo.lol/recipe-images/kale-and-chestnut-stew.webp
---
Remove any large stems from @kale{3 c} and thinly slice into ribbons.
+7 -1
View File
@@ -1,9 +1,15 @@
---
title: Spicy & Crunchy Garlic Tofu (Kkanpoong Tofu)
servings: 2
category: uncategorized
category: dinner
source: https://thekoreanvegan.com/spicy-crunchy-garlic-tofu-kkampoong-tofu/
description:
image: https://roux.roo.lol/recipe-images/kkanpoong-tofu.webp
tags:
- vegetarian
- asian
- korean
- tofu
---
To a large #bowl{}, add a pinch of @salt{} and 2 tablespoons of @potato starch{} to @tofu{1 16 ounce block, extra firm, pressed and chopped into 1/2 inch bite sized chunks}. Gently toss @tofu{} to make sure they are all evenly coated. Set aside.
+8 -2
View File
@@ -1,13 +1,19 @@
---
title: Korean Shrimp Tacos
servings: 2
category: main course
category: dinner
cuisine: Korean-Mexican Fusion
tags: fusion,garnish-and-gather,korean,shrimp,tacos
tags:
- seafood
- shrimp
- asian
- korean
- mexican
source: Unknown
description: Crispy shrimp tacos with gochujang sauce and bok choy rice salad
prep_time: 25 minutes
cook_time: 25 minutes
image: https://roux.roo.lol/recipe-images/korean-shrimp-tacos.webp
---
In a #pot{}, bring 1 1/2 cups @water{} & @salt{1/4 teaspoon} to a boil.
@@ -1,11 +1,16 @@
---
title: Kung Pao Shrimp with Sichuan Roasted Green Beans
servings: 2
category: main course
tags: chinese,garnish-and-gather,kung pao,shrimp
category: dinner
tags:
- seafood
- shrimp
- asian
- chinese
source: Unknown
description:
prep_time: 25 minutes
image: https://roux.roo.lol/recipe-images/kung-pao-shrimp-with-sichuan-roasted-green-beans.webp
---
Preheat #oven{} to 425°.
+6 -2
View File
@@ -1,10 +1,14 @@
---
title: Lactation cookies
servings: 1
category: Cookies
tags: cookies
category: lunch
tags:
- vegetarian
- dessert
- snack
source: Mealie
description:
image: https://roux.roo.lol/recipe-images/lactation-cookies.webp
---
Preheat #oven{} to 350°.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Lactation Cookies
servings: 12
category: Cookies
category: lunch
source: Mealie
image: https://roux.roo.lol/recipe-images/lactation-cookies-2.webp
tags:
- vegetarian
- dessert
- snack
---
@butter{1%cup}
+8 -2
View File
@@ -1,10 +1,16 @@
---
title: Lentil Soup with Lemon and Turmeric
servings: 8
category: uncategorized
category: lunch
source: https://www.inspiredtaste.net/40400/lentil-soup/
description: This is our favorite lentil soup recipe. I make this soup with lentils, carrots, turmeric, and fresh lemon whenever we are in need of some healthy comfort food. It's savory, satisfying, and utterly delicious. I like quite a bit of fresh lemon in this soup and actually serve soup with slices of lemon. This adds even more lemony flavor and shows that lemon was added to soup.
image: https://kitchen.roo.lol/data/images/47a68b65-c916-4c5d-86f2-ea989ea310a7.webp
image: https://roux.roo.lol/recipe-images/lentil-soup-with-lemon-and-turmeric.webp
tags:
- vegetarian
- vegan
- soup
- gluten-free
- indian
---
Heat @olive oil{2 tablespoons} in a large #pot{} (like a #Dutch oven{}) over medium heat. Add @onions{2 cups, finely chopped (1 medium onion)}, @carrot{1 1/2 cups, chopped (2 large carrots)}, and @salt{1/4 teaspoon} of and cook, stirring occasionally until they are softened and starting to smell sweet, about ~{5 to 7 minutes}. Stir in @garlic{2 teaspoons, minced (3 cloves)}, @ground cumin{1 teaspoon}, @ground coriander{1/2 teaspoon}, @fresh ground black pepper{1/2 teaspoon}, and @ground turmeric{1/2 teaspoon} and cook for ~{30 seconds}.
+7 -1
View File
@@ -1,8 +1,14 @@
---
title: Moroccan Spiced Lentil & Chickpea Soup
servings: 1
category: Soup
category: lunch
source: Rebel Recipes
image: https://roux.roo.lol/recipe-images/moroccan-spiced-lentil-chickpea-soup.webp
tags:
- vegetarian
- vegan
- soup
- moroccan
---
In a large pan, add @olive oil{2%tbsp} and @onion{1%large}(chopped); cook on medium heat for 7-8 minutes until soft and browning.
@@ -1,8 +1,14 @@
---
title: Moroccan Spiced Lentil & Chickpea Soup
servings: 1
category: Soup
category: lunch
source: Rebel Recipes
image: https://roux.roo.lol/recipe-images/moroccan-spiced-lentil-and-chickpea-soup.webp
tags:
- vegetarian
- vegan
- soup
- moroccan
---
In a large pan, add @olive oil{2%tbsp} and @onion{1%large}(chopped); cook on medium heat for 7-8 minutes until soft and browning.
+5 -4
View File
@@ -1,13 +1,14 @@
---
title: Orange Rolls
servings: 8
category: uncategorized
category: lunch
source: https://cooking.nytimes.com/recipes/1023939-orange-rolls
description: "Citrusy cinnamon rolls made without yeast, perfumed with fresh orange zest and finished with an orange-cream cheese glaze."
tags:
- breakfast
- rolls
- orange
- vegetarian
- dessert
- bread
image: https://roux.roo.lol/recipe-images/orange-rolls.webp
---
Make the dough: Heat the #oven to 375°F. Place @light brown sugar{1/3%cup} in a small #bowl and zest the @orange{1} directly over it. Gently rub the zest into the sugar and transfer 2 tablespoons/25 grams of the orange sugar to a large #bowl to use for the dough. Save the rest of the orange sugar for the filling.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Palak Paneer
servings: 4
category: Indian
category: dinner
source: Mealie
image: https://roux.roo.lol/recipe-images/palak-paneer.webp
tags:
- vegetarian
- indian
- paneer
---
Preheat the #Instant Pot by selecting Sauté and adjust to More for high heat. When the inner cooking pot is hot, add @peanut oil{2%tbsp} and heat until it is shimmering. Add @garlic cloves{5}(minced), @ginger{2%tsp}(minced), and @serrano or jalapeño chile{1}(minced), and sauté for ~{1%minute} or until fragrant.
+6 -2
View File
@@ -1,10 +1,14 @@
---
title: Passion Fruit Curd Recipe
servings: 10
category: uncategorized
category: lunch
source: https://www.theflavorbender.com/make-passion-fruit-curd/#recipe
description: Makes about 1 1/4 cups of passion fruit curd
image: https://kitchen.roo.lol/data/images/803d123d-d98f-4a68-a820-e47c88b7a66a.webp
image: https://roux.roo.lol/recipe-images/passion-fruit-curd-recipe.webp
tags:
- vegetarian
- gluten-free
- dessert
---
Indirect Heat Method
+5 -2
View File
@@ -1,13 +1,16 @@
---
title: Pecan-Brown Butter Trout
servings: 2
category: main course
category: dinner
cuisine: American
tags: brown butter,garnish-and-gather,pecan,sweet potatoes,trout
tags:
- seafood
- fish
source: Unknown
description: Pan-seared trout with pecan-brown butter sauce, served with herbed sweet potatoes, radishes, and wilted greens
prep_time: 30 minutes
cook_time: 30 minutes
image: https://roux.roo.lol/recipe-images/pecan-brown-butter-trout.webp
---
Preheat #oven{} to 400°F.
+7 -2
View File
@@ -1,13 +1,18 @@
---
title: Ribollita - The Tuscan Stew you Should be Eating Regularly
servings: 10
category: uncategorized
category: lunch
source: https://www.101cookbooks.com/ribollita-recipe/
description: Ribollita, a beautifully thick Tuscan stew made with dark greens, lots of beans, vegetables, olive oil, and thickened with day-old bread. One of my favorites.
image: https://kitchen.roo.lol/data/images/4bc005e2-168b-43bb-a75e-a463eb5bbdc6.webp
image: https://roux.roo.lol/recipe-images/ribollita.webp
prep_time: 15 minutes
cook_timee:25 minutesinutes
totalTime: PT40M
tags:
- vegetarian
- vegan
- soup
- italian
---
In your largest thick-bottomed #pot{} over medium heat combine the @olive oil{3 tbsp + more for drizzling}, @celery{4 stalks, chopped}, @garlic{3 medium cloves, chopped}, @carrots{2 medium or equiv winter squash, chopped}, and @red onion{1 medium, chopped}. Cook for ~{10-15 minutes} sweating the vegetables, but avoid any browning. Stir in the @crushed tomatoes{14oz can} and @red pepper flakes{1/2 tsp, crushed}, and simmer for another ~{10 minutes} or so, long enough for the tomatoes to thicken up a bit. Stir in the @kale{1lb, stems trimmed off + leaves chopped}, @white beans{3 cups / 22oz cooked}, and @water{8 cups / 2 liters}. Bring to a boil, reduce the heat, and simmer until the greens are tender, about ~{15 minutes}.
+7 -2
View File
@@ -4,9 +4,14 @@ description: Pumpkin season is in full swing, and this pumpkin sage soup is the
prep_time: 5 minutes
cook_time: 1 hour 40 minutes
servings: 5
category: uncategorized
category: lunch
source: https://www.skinnytaste.com/roasted-pumpkin-sage-soup
tags: soup, pumpkin, fall, vegetarian-option, gluten-free
tags:
- vegetarian
- vegan
- soup
- fall
image: https://roux.roo.lol/recipe-images/roasted-pumpkin-sage.webp
---
Heat the oven to 400°F.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Saag Paneer
servings: 1
category: Indian
category: dinner
source: Mealie
image: https://roux.roo.lol/recipe-images/saag-paneer.webp
tags:
- vegetarian
- indian
- paneer
---
Preheat the #Instant Pot by selecting Sauté and adjust to More for high heat. When the inner cooking pot is hot, add @peanut oil{2%tbsp} and heat until it is shimmering. Add @garlic cloves{5}(minced), @ginger{2%tsp}(minced), and @serrano or jalapeno chile{1}(minced), and sauté for ~{1%minute} or until fragrant.
+7 -2
View File
@@ -1,10 +1,15 @@
---
title: Sauteed Asparagus with Lemon
servings: 4
category: Thanksgiving
category: lunch
source: https://www.marthastewart.com/316639/sauteed-asparagus-with-lemon
description:
image: https://kitchen.roo.lol/data/images/15498ca3-db5d-461f-a3b7-ce6674fc6bea.webp
image: https://roux.roo.lol/recipe-images/sauteed-asparagus-with-lemon.webp
tags:
- vegetarian
- vegan
- gluten-free
- side
---
In a large #skillet{}, heat @olive oil{1 tablespoon} over medium. Add @asparagus{2 bunches, 14 ounces each, ends trimmed}, and season with @coarse salt{} and @ground pepper{}. Cook, tossing occasionally, until lightly browned and crisp-tender, ~{10 to 15 minutes}, depending on thickness. Add @lemon zest{4 wide strips} and cook ~{1 minute}. Add @lemon juice{from 1/2 lemon}, toss to coat, and serve warm.
+7 -2
View File
@@ -1,10 +1,15 @@
---
title: Slow Cooker Chicken Shawarma
servings: 6
category: uncategorized
category: dinner
source: https://acleanbake.com/slow-cooker-chicken-shawarma/
description: Slow cooker chicken shawarma combines the ease of a slow cooker meal with the complex flavor of a slow-roasted middle eastern chicken feast! This is a quick version of middle eastern favorite: the slow cooker does a lot of the work and it can be prepped ahead of time. Various serving options make this sensational paleo and gluten free dinner recipe adaptable for low carb and Whole30 compliance, too!
image: https://kitchen.roo.lol/data/images/0cea2c65-f549-4f57-97fd-5a1d23941297.webp
image: https://roux.roo.lol/recipe-images/slow-cooker-chicken-shawarma.webp
tags:
- meat
- chicken
- mediterranean
- middle-eastern
---
Place @chicken breasts{2 lbs, boneless, skinless} in #bowl{} of your #slow cooker{}, and add @water{1/2 cup}. Cook on high ~{2 hours} until @chicken{} is cooked through (the juices run clear and @fat{} has rendered out of @chicken{}).
+6 -2
View File
@@ -1,10 +1,14 @@
---
title: Southern Macaroni and Cheese
servings: 10
category: Thanksgiving
category: lunch
source: https://cooking.nytimes.com/recipes/1020515-southern-macaroni-and-cheese
description: There is macaroni and cheese, and then there is special occasion macaroni and cheese like this one. Unlike most recipes, which start with a roux, this one begins with a milk-and-egg base, which gives the dish an incredibly rich, silky taste. It's adapted from Millie Peartree, the owner of Millie Peartree Fish Fry & Soul Food restaurant in the Bronx, who has been making this dish since she was a little girl. The recipe was passed down in her family for generations, but because of the generous amount of cheese used, the dish was only made for events like Christmas and Thanksgiving. Extra-sharp Cheddar adds tartness and a layer of Colby Jack creates a gooey, molten center. If you can't find a Colby Jack blend, shredded mozzarella or a Mexican-style blend will work in its place.
image: https://kitchen.roo.lol/data/images/657048ab-342f-4ca3-84cb-fe9dcb3ae2a4.webp
image: https://roux.roo.lol/recipe-images/southern-macaroni-and-cheese.webp
tags:
- vegetarian
- southern
- pasta
---
Heat #oven{} to 350 degrees. Bring a large #pot{} of generously salted water to a boil. Add @elbow macaroni{1%pound} and cook according to package directions until a little under al dente, about ~{4%minutes}. Transfer to a #colander{} and rinse under cold water to stop cooking. Set aside.
+6 -2
View File
@@ -1,13 +1,17 @@
---
title: Spaghetti Carbonara with Bacon & Crisp Lettuce Salad
servings: 2
category: main dish
category: dinner
cuisine: Italian
tags: bacon,carbonara,garnish-and-gather,italian,pasta,salad
tags:
- meat
- italian
- pasta
source: Unknown
description:
prep_time: 15 minutes
cook_time: 15 minutes
image: https://roux.roo.lol/recipe-images/spaghetti-carbonara.webp
---
Trim root from @lettuce{1 head} and separate into leaves.
+7 -1
View File
@@ -1,8 +1,14 @@
---
title: Spaghetti Squash w/ Chickpeas & Kale
servings: 3
category: Main
category: dinner
source: Love and Lemons
image: https://roux.roo.lol/recipe-images/spaghetti-squash-w-chickpeas-and-kale.webp
tags:
- vegetarian
- vegan
- gluten-free
- vegetable
---
Preheat the oven to 400F.
Prepare your squash following the directions in this post.
+6 -1
View File
@@ -1,8 +1,13 @@
---
title: Skillet Spanakopita (Greek Spinach Feta Pie)
servings: 8
category: Greek
category: dinner
source: From a Chef's Kitchen
image: https://roux.roo.lol/recipe-images/spanakopita.webp
tags:
- vegetarian
- mediterranean
- greek
---
Preheat the oven to 375 degrees.
+4 -3
View File
@@ -2,12 +2,13 @@
title: Spicy Shrimp Paella
servings: 2
prep_time: 25 minutes
category: main course
category: dinner
tags:
- chorizo
- paella
- seafood
- shrimp
- spanish
- rice
image: https://roux.roo.lol/recipe-images/spicy-shrimp-paella.webp
---
In a large sauté #pan, cook @chorizo{2%oz} over medium for ~{3-5%minutes}, until cooked through, then remove, keeping drippings in the pan.
+6 -2
View File
@@ -1,10 +1,14 @@
---
title: Strawberry and Wild Rice Tartlets
servings: 12
category: uncategorized
category: appetizer
source: https://www.bonappetit.com/recipe/strawberry-wild-rice-tartlets
description: This simple six-ingredient dessert is vegan and bursting with texture (crispy wild rice crust) and flavor (rehydrated cherries with fresh strawberries for the filling).
image: https://kitchen.roo.lol/data/images/ed78da5c-1aa5-4d0b-90bc-4d317b7f7b89.webp
image: https://roux.roo.lol/recipe-images/strawberry-and-wild-rice-tartlets.webp
tags:
- vegetarian
- gluten-free-option
- dessert
---
Heat #oven{} to 350°. Brush the cups of one standard 12-cup #muffin pan{} or two standard 6-cup #muffin pans{} with @vegetable oil{}. Bring 6 cups lightly salted @water{} to a boil in a medium #saucepan{}. Add @wild rice{1 cup}, cover, and cook until @water{} evaporates and grains split open, about ~{1½ hours}. Spread out @rice{} on a large rimmed #baking sheet{} and let cool. Reserve #pan{}.
+8 -1
View File
@@ -1,8 +1,15 @@
---
title: Thai Veggie Pad See Ew
servings: 2
category: Thai
category: dinner
source: Unknown
image: https://roux.roo.lol/recipe-images/thai-veggie-pad-see-ew.webp
tags:
- vegetarian
- vegan-option
- asian
- thai
- noodles
---
Bring water to a boil for rice noodles.
+6 -2
View File
@@ -1,12 +1,16 @@
---
title: Tiramisu
servings: 1
category: uncategorized
category: lunch
source: Unknown
description: Georgie Grasso recipe - GGBO winner 2024 with this recipe featured!
image: https://kitchen.roo.lol/data/images/d15cdb2C-71db-42d7-a603-a29389e13bd3.webp
image: https://roux.roo.lol/recipe-images/tiramisu.webp
prep_time: 15 minutes
cook_time: 30 minutes
tags:
- vegetarian
- italian
- dessert
---
Set #oven{} to 355F.
@@ -1,8 +1,14 @@
---
title: Warm Up With a Quick Lemony Chicken Soup
servings: 6
category: Soup
category: lunch
source: EatingWell
image: https://roux.roo.lol/recipe-images/warm-up-with-a-quick-lemony-chicken-soup.webp
tags:
- meat
- chicken
- soup
- gluten-free
---
Heat @olive oil{1%tbsp} in a Dutch oven over medium-high. Add @carrots{3/4%cup} and @yellow onion{1/2%cup}; cook, stirring often, until vegetables are softened, 3 to 4 minutes. Add @garlic cloves{2}(minced) and @crushed red pepper flakes{3/4%tsp}, and cook, stirring constantly, until fragrant, about 1 minute.
+7 -2
View File
@@ -1,12 +1,17 @@
---
title: West African Peanut Chicken
servings: 2
category: main course
tags: chicken,garnish-and-gather,peanut,west african
category: dinner
tags:
- meat
- chicken
- african
- stew
source: Unknown
description:
prep_time: 25 minutes
cook_time: 25 minutes
image: https://roux.roo.lol/recipe-images/west-african-peanut-chicken.webp
---
Mince @fresno pepper{1}—remove seeds and use only half for less heat.
+5 -1
View File
@@ -3,7 +3,11 @@ title: Wheat Berry Salad
servings: 1
description: This healthy wheat berry salad is a delicious fall side dish or lunch with dried cranberries, fresh herbs, walnuts, and a tangy vinaigrette.
source: https://www.loveandlemons.com/wheat-berry-salad/
image: https://kitchen.roo.lol/data/images/eb72067c-28c7-4ae3-88ed-1fc0b9aba762.webp
image: https://roux.roo.lol/recipe-images/wheat-berry-salad.webp
tags:
- vegetarian
- vegan
- grain-bowl
---
= Wheat berries =
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
while IFS='|' read -r file slug; do
url=$(grep "^image:" "$file" | sed 's/^image:[[:space:]]*//')
echo "[$slug] Downloading from $url"
curl -sL -o "recipe-images/$slug.webp" "$url" || echo "[$slug] DOWNLOAD FAILED"
done
+409
View File
@@ -0,0 +1,409 @@
#!/usr/bin/env python3
"""Categorize recipes with category and tags based on content."""
import re
from pathlib import Path
import yaml
WORKDIR = Path("/home/jbrechtel/recipes")
# Recipe classifications: (filename_pattern, {category, tags})
CLASSIFICATIONS = [
("Alain-Ducase-Bread.cook", {
"category": "appetizer",
"tags": ["vegetarian", "french", "cheese"]
}),
("Apple Cider Vinegar Dressing.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free"]
}),
("Arugula Pesto Chicken with Pecans & Roasted Butternut.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "pasta"]
}),
("Arugula Pesto Wheat Berries Recipe.cook", {
"category": "lunch",
"tags": ["vegetarian", "grain-bowl"]
}),
("Asparagus Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "gluten-free", "spring"]
}),
("Authentic Cacio e Pepe Recipe.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "pasta"]
}),
("Baked Chile Relleno with Black Beans.cook", {
"category": "dinner",
"tags": ["vegetarian", "mexican", "beans"]
}),
("Bang Bang Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "asian", "tofu"]
}),
("Barbecue Chicken with Crispy Pan-Fried Okra & Cheddar Biscuits.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "southern"]
}),
("Black Bean and Corn Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free", "mexican"]
}),
("Black Pepper Tofu (Ottolenghi).cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Black Pepper Tofu with Bok Choy.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Blackened Shrimp and Gouda Grits.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "southern"]
}),
("Butter Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "tofu"]
}),
("butternut-turkey-chili.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("Butternut Turkey Chili.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("BUTTERNUT & TURKEY CHILI with sweet peppers, spiced pepitas & queso fresco.cook", {
"category": "dinner",
"tags": ["meat", "turkey", "chili", "soup"]
}),
("Cabbage_Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "gluten-free"]
}),
("Cajun Shrimp and Sausage Vegetable Foil Packets.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "cajun", "sausage"]
}),
("Cajun Spice Mix (for pecans, oysters, etc).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "spice-blend"]
}),
("Caramel Cake.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert"]
}),
("Caramel Icing.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert"]
}),
("cauliflower-milanese.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "vegetable"]
}),
("Chana Chickpea Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "indian", "gluten-free"]
}),
("Chana Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "indian", "gluten-free"]
}),
("Chicken and Pumpkin Gnocchi with Ricotta.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "pasta", "fall"]
}),
("Chickpea Butter Curry.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "curry", "vegan-option"]
}),
("Chickpea_Butter_Curry.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "curry", "vegan-option"]
}),
("Chinese Orange Shrimp.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian"]
}),
("Chocolate_Mousse_Cake_with_Raspberries.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "chocolate"]
}),
("Cilantro Pesto Shrimp Over Orzo.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "pasta"]
}),
("Crispy Roasted Chickpeas (Garbanzo Beans).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "gluten-free", "snack"]
}),
("Crispy_Roasted_Chickpeas_(Garbanzo_Beans).cook", {
"category": "appetizer",
"tags": ["vegetarian", "vegan", "gluten-free", "snack"]
}),
("Crispy Tofu With Cashews and Blistered Snap Peas.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "tofu", "vegan-option"]
}),
("Dried Fava Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "mexican"]
}),
("Easy Lemon Rosemary White Bean Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free"]
}),
("Easy_Lemon_Rosemary_White_Bean_Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free"]
}),
("Easy Vegetarian Chili.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan", "chili", "soup"]
}),
("example-fried-rice.cook", {
"category": "dinner",
"tags": ["meat", "asian", "rice"]
}),
("Fettucine with spiced cherry tomato sauce.cook", {
"category": "dinner",
"tags": ["vegetarian", "italian", "pasta"]
}),
("Gaja's Bulgogi Lettuce Wraps.cook", {
"category": "dinner",
"tags": ["meat", "asian", "korean"]
}),
("Gochugaru Honey Salmon.cook", {
"category": "dinner",
"tags": ["seafood", "salmon", "asian", "korean"]
}),
("Green_Beans_with_Lemon_and_Garlic.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "gluten-free", "side"]
}),
("indian-spiced-chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "indian"]
}),
("Indian Spiced Chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "indian"]
}),
("Italian Sausage and Delicata Rigatoni.cook", {
"category": "dinner",
"tags": ["meat", "sausage", "pasta", "italian"]
}),
("Kale and Chestnut Stew.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "soup", "fall"]
}),
("Kkanpoong Tofu.cook", {
"category": "dinner",
"tags": ["vegetarian", "asian", "korean", "tofu"]
}),
("Korean Shrimp Tacos.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian", "korean", "mexican"]
}),
("Kung Pao Shrimp with Sichuan Roasted Green Beans.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "asian", "chinese"]
}),
("Lactation cookies.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "snack"]
}),
("Lactation_cookies.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "snack"]
}),
("Lentil Soup with Lemon and Turmeric.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "gluten-free", "indian"]
}),
("Moroccan_Spiced_Lentil_and_Chickpea_Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "moroccan"]
}),
("Moroccan Spiced Lentil & Chickpea Soup.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "moroccan"]
}),
("Orange Rolls.cook", {
"category": "lunch",
"tags": ["vegetarian", "dessert", "bread"]
}),
("Palak Paneer.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "paneer"]
}),
("Passion Fruit Curd Recipe.cook", {
"category": "lunch",
"tags": ["vegetarian", "gluten-free", "dessert"]
}),
("Pecan-Brown Butter Trout.cook", {
"category": "dinner",
"tags": ["seafood", "fish"]
}),
("Ribollita.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "italian"]
}),
("Roasted Pumpkin Sage.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "soup", "fall"]
}),
("Saag Paneer.cook", {
"category": "dinner",
"tags": ["vegetarian", "indian", "paneer"]
}),
("Sauteed Asparagus with Lemon.cook", {
"category": "lunch",
"tags": ["vegetarian", "vegan", "gluten-free", "side"]
}),
("sheet-pan-miso-chicken-with-radishes-and-lime.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "asian", "japanese"]
}),
("sheet-pan-shrimp-oreganata.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "italian"]
}),
("shrimp-feta.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "mediterranean", "pasta"]
}),
("Slow Cooker Chicken Shawarma.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "mediterranean", "middle-eastern"]
}),
("Southern_Macaroni_and_Cheese.cook", {
"category": "lunch",
"tags": ["vegetarian", "southern", "pasta"]
}),
("Spaghetti Carbonara.cook", {
"category": "dinner",
"tags": ["meat", "italian", "pasta"]
}),
("Spaghetti_Squash_w_Chickpeas_and_Kale.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan", "gluten-free", "vegetable"]
}),
("Spanakopita.cook", {
"category": "dinner",
"tags": ["vegetarian", "mediterranean", "greek"]
}),
("Spicy Shrimp Paella.cook", {
"category": "dinner",
"tags": ["seafood", "shrimp", "spanish", "rice"]
}),
("Strawberry and Wild Rice Tartlets.cook", {
"category": "appetizer",
"tags": ["vegetarian", "gluten-free-option", "dessert"]
}),
("Thai_Veggie_Pad_See_Ew.cook", {
"category": "dinner",
"tags": ["vegetarian", "vegan-option", "asian", "thai", "noodles"]
}),
("Tiramisu.cook", {
"category": "lunch",
"tags": ["vegetarian", "italian", "dessert"]
}),
("Warm Up With a Quick Lemony Chicken Soup.cook", {
"category": "lunch",
"tags": ["meat", "chicken", "soup", "gluten-free"]
}),
("West African Peanut Chicken.cook", {
"category": "dinner",
"tags": ["meat", "chicken", "african", "stew"]
}),
("Wheat Berry Salad.cook", {
"category": "salad",
"tags": ["vegetarian", "vegan", "grain-bowl"]
}),
]
def update_frontmatter(filepath, classification):
"""Update category and tags in the YAML frontmatter."""
content = filepath.read_text(encoding="utf-8")
# Find the YAML frontmatter
m = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not m:
print(f" No frontmatter in {filepath.name}")
return False
fm_text = m.group(1)
lines = fm_text.split('\n')
new_lines = []
in_tags = False
category_updated = False
tags_updated = False
for line in lines:
stripped = line.strip()
if stripped.startswith('category:'):
new_lines.append(f"category: {classification['category']}")
category_updated = True
in_tags = False
elif stripped.startswith('tags:'):
# Skip old tags, we'll add new ones
in_tags = True
tags_updated = True
new_lines.append("tags:")
for tag in classification['tags']:
new_lines.append(f" - {tag}")
elif in_tags:
# Skip old tag lines (indented with -)
if stripped.startswith('-') or stripped == '':
continue
else:
in_tags = False
new_lines.append(line)
else:
new_lines.append(line)
if not category_updated:
# Add category before tags or at end of frontmatter
print(f" No category field in {filepath.name}")
if not tags_updated:
# Add tags at end of frontmatter
new_lines.append("tags:")
for tag in classification['tags']:
new_lines.append(f" - {tag}")
new_fm = '\n'.join(new_lines)
new_content = f"---\n{new_fm}\n---" + content[m.end():]
filepath.write_text(new_content, encoding="utf-8")
return True
def main():
updated = 0
errors = 0
for filename, classification in CLASSIFICATIONS:
fp = WORKDIR / filename
if not fp.exists():
print(f"NOT FOUND: {filename}")
errors += 1
continue
try:
update_frontmatter(fp, classification)
print(f"UPDATED: {filename}{classification['category']} [{', '.join(classification['tags'])}]")
updated += 1
except Exception as e:
print(f"ERROR: {filename}: {e}")
errors += 1
print(f"\n{'='*50}")
print(f"Total: {len(CLASSIFICATIONS)} | Updated: {updated} | Errors: {errors}")
if __name__ == "__main__":
main()
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
slug="$1"
url="$2"
echo "[$slug] Fetching $url" >&2
html=$(curl -sL --max-time 15 "$url" 2>/dev/null) || { echo "[$slug] FETCH FAILED" >&2; echo ""; exit 0; }
# Try multiple og:image patterns
img_url=$(echo "$html" | grep -oP 'property="og:image"\s+content="[^"]*"' | sed 's/.*content="//;s/"//' | head -1)
if [ -z "$img_url" ]; then
img_url=$(echo "$html" | grep -oP 'name="og:image"\s+content="[^"]*"' | sed 's/.*content="//;s/"//' | head -1)
fi
if [ -z "$img_url" ]; then
img_url=$(echo "$html" | grep -oP 'content="[^"]*"[^>]*property="og:image"' | sed 's/.*content="//;s/".*//' | head -1)
fi
if [ -n "$img_url" ]; then
echo "[$slug] Found: $img_url" >&2
echo "$img_url"
else
echo "[$slug] No og:image found" >&2
fi
+242
View File
@@ -0,0 +1,242 @@
#!/usr/bin/env python3
"""Final attempt: search DDG text, scrape recipe pages for actual images."""
import csv
import json
import re
import sys
import time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
from ddgs import DDGS
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
}
SKIP_DOMAINS = {"pinterest", "facebook", "instagram", "twitter", "youtube", "tiktok"}
MIN_IMAGE_SIZE = 10000 # 10KB minimum for a recipe photo
def search_url(query: str) -> str | None:
"""Search and return first relevant recipe page URL."""
try:
results = list(DDGS().text(query, max_results=8))
except Exception as e:
print(f" Search error: {e}", file=sys.stderr)
return None
for r in results:
url = r.get("href", "")
domain = url.split("/")[2] if "//" in url else ""
if any(s in domain for s in SKIP_DOMAINS):
continue
# Prefer recipe sites
if any(kw in domain for kw in ["recipe", "cook", "food", "kitchen", "nytimes", "loveandlemons"]):
return url
# Return first non-wikipedia result
for r in results:
url = r.get("href", "")
if "wikipedia.org" not in url:
return url
return None
def find_recipe_images(url: str) -> list[str]:
"""Fetch a page and find actual recipe/food images."""
try:
resp = requests.get(url, headers=HEADERS, timeout=15, allow_redirects=True)
resp.raise_for_status()
except requests.RequestException:
return []
soup = BeautifulSoup(resp.text, "html.parser")
images = []
# 1. Check JSON-LD for recipe image
for script in soup.find_all("script", type="application/ld+json"):
try:
data = json.loads(script.string)
except (json.JSONDecodeError, TypeError):
continue
# Handle list or single
items = data if isinstance(data, list) else [data]
for item in items:
if not isinstance(item, dict):
continue
if item.get("@type") == "Recipe":
img = item.get("image")
if isinstance(img, str):
images.append(img)
elif isinstance(img, list):
for i in img:
if isinstance(i, str):
images.append(i)
elif isinstance(i, dict):
u = i.get("contentUrl") or i.get("url", "")
if u:
images.append(u)
elif isinstance(img, dict):
u = img.get("contentUrl") or img.get("url", "")
if u:
images.append(u)
# 2. Check og:image
for meta in soup.find_all("meta"):
content = meta.get("content", "")
if (meta.get("property") == "og:image" or meta.get("name") == "og:image" or meta.get("name") == "twitter:image"):
if content and "logo" not in content.lower():
images.append(content)
# 3. Check all img tags for large, relevant images
for img in soup.find_all("img"):
src = img.get("src") or img.get("data-src") or ""
if not src.startswith("http"):
continue
src_lower = src.lower()
if any(kw in src_lower for kw in ["logo", "avatar", "icon", "banner", "pixel", "spacer", "thumb"]):
continue
# Check for recipe-related class/id
parent_classes = ""
parent = img.parent
if parent:
parent_classes = " ".join(parent.get("class", []) or []) + " " + (parent.get("id") or "")
if any(kw in parent_classes.lower() for kw in ["logo", "nav", "header", "footer", "menu", "icon"]):
continue
images.append(src)
# Deduplicate
seen = set()
unique = []
for img in images:
if img not in seen:
seen.add(img)
unique.append(img)
return unique
def download_image(url: str, dest: Path) -> bool:
"""Download image, validate it's a real image."""
try:
resp = requests.get(url, headers=HEADERS, timeout=30, stream=True)
resp.raise_for_status()
ct = resp.headers.get("content-type", "")
if not ct.startswith("image/"):
return False
content = resp.content
if len(content) < MIN_IMAGE_SIZE:
return False
dest.write_bytes(content)
return True
except requests.RequestException:
return False
def get_title(filepath: Path) -> str:
content = filepath.read_text(encoding="utf-8")
m = re.search(r"^title:\s*(.+)$", content, re.MULTILINE)
if m:
return m.group(1).strip()
return filepath.stem.replace("_", " ").replace("-", " ")
def add_image_field(filepath: Path, slug: str):
url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = filepath.read_text(encoding="utf-8")
if re.search(r"^image:", content, re.MULTILINE):
content = re.sub(r"^image:.*$", f"image: {url}", count=1, flags=re.MULTILINE, string=content)
else:
content = re.sub(r"^---$", f"image: {url}\n---", count=1, flags=re.MULTILINE, string=content)
filepath.write_text(content, encoding="utf-8")
print(f" Updated {filepath.name}", file=sys.stderr)
def get_source_url(filepath: Path) -> str | None:
content = filepath.read_text(encoding="utf-8")
m = re.search(r"^source:\s*(.+)$", content, re.MULTILINE)
if m:
val = m.group(1).strip()
if val.startswith("http"):
return val
return None
def main():
csv_file = WORKDIR / "docs" / "no-image-has-fm.csv"
recipes = []
with open(csv_file) as f:
reader = csv.reader(f, delimiter="|")
for row in reader:
if len(row) >= 2:
recipes.append((row[0].strip(), row[1].strip()))
success = []
failed = []
for filename, slug in recipes:
filepath = WORKDIR / filename
if not filepath.exists():
failed.append(slug)
continue
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
# Skip if already has image AND file exists
content = filepath.read_text(encoding="utf-8")
has_field = bool(re.search(r"^image:", content, re.MULTILINE))
has_file = dest.exists()
if has_field and has_file and dest.stat().st_size > 10000:
print(f"[{slug}] Already done, skipping", file=sys.stderr)
success.append(slug)
continue
title = get_title(filepath)
query = f"{title} recipe"
print(f"[{slug}] Searching: {query}", file=sys.stderr)
page_url = search_url(query)
if not page_url:
print(f" No search results", file=sys.stderr)
failed.append(slug)
continue
print(f" Page: {page_url}", file=sys.stderr)
time.sleep(0.3)
img_urls = find_recipe_images(page_url)
if not img_urls:
print(f" No images found on page", file=sys.stderr)
failed.append(slug)
continue
downloaded = False
for img_url in img_urls[:5]:
print(f" Trying: {img_url[:80]}...", file=sys.stderr)
if download_image(img_url, dest):
print(f" Downloaded ({dest.stat().st_size} bytes)", file=sys.stderr)
add_image_field(filepath, slug)
downloaded = True
break
time.sleep(0.2)
if downloaded:
success.append(slug)
else:
failed.append(slug)
time.sleep(0.5)
print(f"\n=== Results ===", file=sys.stderr)
print(f"Success: {len(success)}", file=sys.stderr)
print(f"Failed: {len(failed)}", file=sys.stderr)
if failed:
print(f"Failed: {', '.join(failed)}", file=sys.stderr)
if __name__ == "__main__":
main()
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""Find images for remaining 6 recipes."""
import re, sys, time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
from ddgs import DDGS
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"}
recipes = [
("Arugula Pesto Chicken with Pecans & Roasted Butternut.cook", "arugula-pesto-chicken-with-pecans-roasted-butternut", "Arugula Pesto Chicken Pecans Roasted Butternut recipe garnishandgather"),
("Bang Bang Tofu.cook", "bang-bang-tofu", "Bang Bang Tofu recipe"),
("Chana Chickpea Salad.cook", "chana-chickpea-salad", "Chana Chickpea Salad recipe"),
("Gaja's Bulgogi Lettuce Wraps.cook", "gaja-s-bulgogi-lettuce-wraps", "Gaja Bulgogi Lettuce Wraps recipe garnishandgather"),
("Pecan-Brown Butter Trout.cook", "pecan-brown-butter-trout", "Pecan Brown Butter Trout recipe"),
("West African Peanut Chicken.cook", "west-african-peanut-chicken", "West African Peanut Chicken recipe"),
]
for file, slug, query in recipes:
fp = WORKDIR / file
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
if dest.exists() and dest.stat().st_size > 10000:
print(f"[{slug}] Already done")
continue
print(f"[{slug}] Searching: {query}")
try:
results = list(DDGS().text(query, max_results=5))
except Exception as e:
print(f" Search error: {e}")
continue
found = False
for r in results:
url = r.get("href", "")
if not url or any(s in url for s in ["pinterest","facebook","instagram"]):
continue
print(f" Fetching: {url}")
try:
resp = requests.get(url, headers=HEADERS, timeout=15)
resp.raise_for_status()
except Exception as e:
print(f" Failed: {e}")
continue
soup = BeautifulSoup(resp.text, "html.parser")
img_urls = []
# og:image
for meta in soup.find_all("meta"):
c = meta.get("content", "")
p = (meta.get("property") or "").lower()
n = (meta.get("name") or "").lower()
if ("og:image" in p or "og:image" in n or "twitter:image" in n) and c and "logo" not in c.lower():
img_urls.append(c)
# img tags
for img in soup.find_all("img"):
src = img.get("src") or img.get("data-src") or ""
if src.startswith("http") and "logo" not in src.lower() and "icon" not in src.lower():
img_urls.append(src)
for img_url in img_urls[:5]:
try:
r2 = requests.get(img_url, headers=HEADERS, timeout=15)
r2.raise_for_status()
ct = r2.headers.get("content-type", "")
if ct.startswith("image/") and len(r2.content) > 10000:
dest.write_bytes(r2.content)
print(f" Downloaded ({len(r2.content)} bytes): {img_url[:60]}")
found = True
break
except:
pass
if found:
break
time.sleep(0.3)
if found:
# Add image field
url_val = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = fp.read_text(encoding="utf-8")
if re.search(r"^image:", content, re.MULTILINE):
content = re.sub(r"^image:.*$", f"image: {url_val}", count=1, flags=re.MULTILINE, string=content)
else:
content = re.sub(r"^---$", f"image: {url_val}\n---", count=1, flags=re.MULTILINE, string=content)
fp.write_text(content, encoding="utf-8")
print(f" Updated image field")
else:
print(f" FAILED")
time.sleep(0.5)
print("\nDone!")
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
"""Fix the broken YAML frontmatter: move image field inside YAML, and convert non-WebP images."""
import re, subprocess, sys
from pathlib import Path
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
def fix_frontmatter(content: str) -> str:
"""Move image: field inside the YAML block if it's outside."""
# Check if image: is before the opening ---
lines = content.split('\n')
# Find the first --- line
first_hr = -1
for i, line in enumerate(lines):
if line.strip() == '---':
first_hr = i
break
if first_hr <= 0:
return content # No frontmatter or image is at first line
# Check if the line just before the first --- has image:
if first_hr > 0 and lines[first_hr - 1].startswith('image:'):
# Extract the image line
img_line = lines[first_hr - 1]
# Remove it from before ---
del lines[first_hr - 1]
# Now first_hr is one index less (or same if we deleted the line before)
# Find the closing ---
closing_hr = -1
for i in range(first_hr, len(lines)):
if lines[i].strip() == '---':
closing_hr = i
break
if closing_hr > first_hr:
# Insert image line before the closing ---
lines.insert(closing_hr, img_line)
else:
# Insert after the closing --- (fallback)
lines.insert(first_hr + 1, img_line)
return '\n'.join(lines)
def fix_all_frontmatter():
"""Fix frontmatter for all .cook files."""
fixed = 0
for f in sorted(WORKDIR.glob("*.cook")):
content = f.read_text(encoding="utf-8")
fixed_content = fix_frontmatter(content)
if fixed_content != content:
f.write_text(fixed_content, encoding="utf-8")
print(f" Fixed: {f.name}")
fixed += 1
print(f"\nFixed {fixed} files with mis-placed image fields")
return fixed
def convert_images():
"""Convert non-WebP images to actual WebP format."""
converted = 0
for img in sorted(WORKDIR.glob("recipe-images/*.webp")):
mime = subprocess.run(
["file", "-b", "--mime-type", str(img)],
capture_output=True, text=True
).stdout.strip()
if mime != "image/webp":
print(f" Converting {img.name} (mime: {mime})")
# Use temp file to avoid corruption
tmp = img.with_suffix(".webp.tmp")
result = subprocess.run(
["convert", str(img), str(tmp)],
capture_output=True, text=True
)
if result.returncode == 0 and tmp.exists():
tmp.replace(img)
print(f" Converted successfully")
converted += 1
else:
print(f" Convert failed: {result.stderr}")
print(f"\nConverted {converted} images to proper WebP")
return converted
if __name__ == "__main__":
print("=== Fixing YAML frontmatter ===")
fix_all_frontmatter()
print("\n=== Converting image formats ===")
convert_images()
# Final check
print("\n=== Final verification ===")
bad = 0
for f in sorted(WORKDIR.glob("*.cook")):
content = f.read_text(encoding="utf-8")
# Check if image: is between --- markers
if "image:" in content:
# Find the opening ---
parts = content.split('---', 2)
if len(parts) >= 3:
if "image:" not in parts[1]:
print(f" STILL BROKEN: {f.name}")
bad += 1
if bad == 0:
print(" All files have image: inside YAML block ✅")
webp_count = 0
non_webp_count = 0
for img in sorted(WORKDIR.glob("recipe-images/*.webp")):
mime = subprocess.run(
["file", "-b", "--mime-type", str(img)],
capture_output=True, text=True
).stdout.strip()
if mime == "image/webp":
webp_count += 1
else:
non_webp_count += 1
if non_webp_count <= 5:
print(f" NOT WEBP: {img.name} ({mime})")
print(f" WebP images: {webp_count}, Non-WebP: {non_webp_count}")
+171
View File
@@ -0,0 +1,171 @@
#!/usr/bin/env python3
"""Scrape og:image from recipe source URLs, download images, update .cook files."""
import csv
import os
import re
import sys
import time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}
def get_source_url(filepath: Path) -> str | None:
"""Extract the source URL from a .cook file's YAML frontmatter."""
content = filepath.read_text(encoding="utf-8")
match = re.search(r"^source:\s*(.+)$", content, re.MULTILINE)
if not match:
return None
val = match.group(1).strip()
# Only return actual URLs
if val.startswith("http://") or val.startswith("https://"):
return val
return None
def fetch_og_image(url: str, timeout: int = 20) -> str | None:
"""Fetch a page and extract og:image URL."""
try:
resp = requests.get(url, headers=HEADERS, timeout=timeout, allow_redirects=True)
resp.raise_for_status()
except requests.RequestException as e:
print(f" FETCH FAILED: {e}", file=sys.stderr)
return None
soup = BeautifulSoup(resp.text, "html.parser")
# Try og:image meta tag
for meta in soup.find_all("meta"):
if meta.get("property") == "og:image" and meta.get("content"):
return meta["content"]
if meta.get("name") == "og:image" and meta.get("content"):
return meta["content"]
# Try twitter:image
for meta in soup.find_all("meta"):
if meta.get("name") == "twitter:image" and meta.get("content"):
return meta["content"]
# Try finding the first large image (common in recipe sites)
for img in soup.find_all("img"):
src = img.get("src") or ""
if "logo" in src.lower() or "avatar" in src.lower() or "icon" in src.lower():
continue
if src.startswith("http") and any(kw in src.lower() for kw in ["upload", "wp-content", "images"]):
return src
return None
def download_image(url: str, dest: Path) -> bool:
"""Download an image from URL to destination path."""
try:
resp = requests.get(url, headers=HEADERS, timeout=30, stream=True)
resp.raise_for_status()
dest.write_bytes(resp.content)
return True
except requests.RequestException as e:
print(f" DOWNLOAD FAILED: {e}", file=sys.stderr)
return False
def add_image_field(filepath: Path, slug: str):
"""Add or update the image field in a .cook file's YAML frontmatter."""
url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = filepath.read_text(encoding="utf-8")
# If image field already exists, replace it
if re.search(r"^image:", content, re.MULTILINE):
content = re.sub(r"^image:.*$", f"image: {url}", content, count=1, flags=re.MULTILINE)
else:
# Insert before closing ---
content = re.sub(r"^---$", f"image: {url}\n---", content, count=1, flags=re.MULTILINE)
filepath.write_text(content, encoding="utf-8")
print(f" Updated image field: {filepath.name}", file=sys.stderr)
def process_recipe(filepath: Path, slug: str) -> bool:
"""Process a single recipe: find image, download, update frontmatter."""
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
# Skip if already downloaded
if dest.exists():
print(f"[{slug}] Image already exists, skipping download", file=sys.stderr)
add_image_field(filepath, slug)
return True
# Try to get source URL and scrape image
src_url = get_source_url(filepath)
if src_url:
print(f"[{slug}] Scraping {src_url}", file=sys.stderr)
img_url = fetch_og_image(src_url)
if img_url:
print(f" Found: {img_url}", file=sys.stderr)
if download_image(img_url, dest):
print(f" Downloaded to {dest.name}", file=sys.stderr)
add_image_field(filepath, slug)
return True
else:
print(f" Download failed", file=sys.stderr)
return False
def main():
csv_file = WORKDIR / "docs" / "no-image-has-fm.csv"
if not csv_file.exists():
print(f"CSV not found: {csv_file}", file=sys.stderr)
sys.exit(1)
recipes = []
with open(csv_file) as f:
reader = csv.reader(f, delimiter="|")
for row in reader:
if len(row) >= 2:
recipes.append((row[0].strip(), row[1].strip()))
print(f"Processing {len(recipes)} recipes...", file=sys.stderr)
success = []
failed = []
for filename, slug in recipes:
filepath = WORKDIR / filename
if not filepath.exists():
print(f"[{slug}] File not found: {filepath}", file=sys.stderr)
failed.append(slug)
continue
ok = process_recipe(filepath, slug)
if ok:
success.append(slug)
else:
failed.append(slug)
# Be polite to servers
time.sleep(0.5)
print(f"\n=== Results ===", file=sys.stderr)
print(f"Success: {len(success)}", file=sys.stderr)
print(f"Failed: {len(failed)}", file=sys.stderr)
if failed:
print(f"Failed slugs: {', '.join(failed)}", file=sys.stderr)
# Write failed slugs to file for retry
if failed:
with open(WORKDIR / "docs" / "failed-images.csv", "w") as f:
for slug in failed:
f.write(f"{slug}\n")
if __name__ == "__main__":
main()
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""Search the web for recipe images, download them, and update .cook files.
Uses DuckDuckGo search to find recipe pages, then scrapes og:image.
"""
import csv
import os
import re
import sys
import time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
from duckduckgo_search import DDGS
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
}
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".gif"}
def fetch_og_image(url: str) -> str | None:
"""Fetch a page and extract og:image URL."""
try:
resp = requests.get(url, headers=HEADERS, timeout=15, allow_redirects=True)
resp.raise_for_status()
except requests.RequestException:
return None
soup = BeautifulSoup(resp.text, "html.parser")
# Try og:image meta tag (property or name)
for meta in soup.find_all("meta"):
prop = (meta.get("property") or "").lower()
name = (meta.get("name") or "").lower()
content = meta.get("content", "")
if "og:image" in prop and content:
return content
if "og:image" in name and content:
return content
if "twitter:image" in name and content:
return content
# Try schema.org JSON-LD
for script in soup.find_all("script", type="application/ld+json"):
import json
try:
data = json.loads(script.string)
if isinstance(data, dict):
img = data.get("image")
if isinstance(img, str) and img.startswith("http"):
return img
if isinstance(img, dict):
url = img.get("contentUrl") or img.get("url", "")
if url.startswith("http"):
return url
if isinstance(img, list) and img:
first = img[0]
if isinstance(first, str):
return first
if isinstance(first, dict):
url = first.get("contentUrl") or first.get("url", "")
if url.startswith("http"):
return url
except (json.JSONDecodeError, AttributeError):
pass
return None
def search_and_find_image(query: str) -> str | None:
"""Search DuckDuckGo for a recipe and find og:image."""
try:
results = list(DDGS().text(query, max_results=5))
except Exception as e:
print(f" Search error: {e}", file=sys.stderr)
return None
for r in results:
url = r.get("href", "")
if not url or "pinterest" in url or "facebook" in url or "instagram" in url:
continue
print(f" Trying: {url}", file=sys.stderr)
img = fetch_og_image(url)
if img:
print(f" Found image: {img}", file=sys.stderr)
return img
time.sleep(0.3)
return None
def download_image(url: str, dest: Path) -> bool:
"""Download an image from URL to destination path."""
try:
resp = requests.get(url, headers=HEADERS, timeout=30, stream=True)
resp.raise_for_status()
dest.write_bytes(resp.content)
return True
except requests.RequestException as e:
print(f" Download failed: {e}", file=sys.stderr)
return False
def add_image_field(filepath: Path, slug: str):
"""Add or update the image field in a .cook file's YAML frontmatter."""
url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = filepath.read_text(encoding="utf-8")
if re.search(r"^image:", content, re.MULTILINE):
content = re.sub(r"^image:.*$", f"image: {url}", count=1, flags=re.MULTILINE, string=content)
else:
content = re.sub(r"^---$", f"image: {url}\n---", count=1, flags=re.MULTILINE, string=content)
filepath.write_text(content, encoding="utf-8")
print(f" Updated {filepath.name}", file=sys.stderr)
def get_source_url(filepath: Path) -> str | None:
"""Extract source URL from .cook frontmatter."""
content = filepath.read_text(encoding="utf-8")
match = re.search(r"^source:\s*(.+)$", content, re.MULTILINE)
if match:
val = match.group(1).strip()
if val.startswith("http://") or val.startswith("https://"):
return val
return None
def process_recipe(filename: str, slug: str) -> bool:
"""Try to find and download an image for a recipe."""
filepath = WORKDIR / filename
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
if dest.exists():
print(f"[{slug}] Already exists", file=sys.stderr)
add_image_field(filepath, slug)
return True
# Strategy 1: Try source URL if available
src_url = get_source_url(filepath)
if src_url:
print(f"[{slug}] Trying source URL: {src_url}", file=sys.stderr)
img = fetch_og_image(src_url)
if img:
if download_image(img, dest):
print(f" Downloaded from source", file=sys.stderr)
add_image_field(filepath, slug)
return True
# Strategy 2: Search by recipe name
# Get the title from frontmatter
content = filepath.read_text(encoding="utf-8")
title_match = re.search(r"^title:\s*(.+)$", content, re.MULTILINE)
if title_match:
query = title_match.group(1).strip() + " recipe"
else:
query = filename.replace(".cook", "").replace("_", " ").replace("-", " ") + " recipe"
print(f"[{slug}] Searching: {query}", file=sys.stderr)
img = search_and_find_image(query)
if img and download_image(img, dest):
print(f" Downloaded from search", file=sys.stderr)
add_image_field(filepath, slug)
return True
# Strategy 3: Try with "og:image" or "recipe image" variations
query2 = query + " image"
print(f"[{slug}] Searching (alt): {query2}", file=sys.stderr)
img = search_and_find_image(query2)
if img and download_image(img, dest):
print(f" Downloaded from alt search", file=sys.stderr)
add_image_field(filepath, slug)
return True
return False
def main():
# First process the no-image-has-fm list
csv_file = WORKDIR / "docs" / "no-image-has-fm.csv"
if not csv_file.exists():
print(f"CSV not found: {csv_file}", file=sys.stderr)
sys.exit(1)
recipes = []
with open(csv_file) as f:
reader = csv.reader(f, delimiter="|")
for row in reader:
if len(row) >= 2:
recipes.append((row[0].strip(), row[1].strip()))
success = []
failed = []
for filename, slug in recipes:
filepath = WORKDIR / filename
if not filepath.exists():
failed.append(slug)
continue
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
if dest.exists() and re.search(r"^image:", filepath.read_text(), re.MULTILINE):
print(f"[{slug}] Already processed, skipping", file=sys.stderr)
success.append(slug)
continue
ok = process_recipe(filename, slug)
if ok:
success.append(slug)
else:
failed.append(slug)
# Be polite
time.sleep(0.5)
print(f"\n=== Results ===", file=sys.stderr)
print(f"Success: {len(success)}", file=sys.stderr)
print(f"Failed: {len(failed)}", file=sys.stderr)
if failed:
with open(WORKDIR / "docs" / "failed-images.csv", "w") as f:
for s in failed:
f.write(f"{s}\n")
print(f"Failed: {', '.join(failed)}", file=sys.stderr)
if __name__ == "__main__":
main()
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""Search DuckDuckGo Images for recipe photos, download, update .cook files."""
import csv
import re
import sys
import time
from pathlib import Path
import requests
from duckduckgo_search import DDGS
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
}
def download_image(url: str, dest: Path) -> bool:
"""Download an image from URL to destination path."""
try:
resp = requests.get(url, headers=HEADERS, timeout=30, stream=True)
resp.raise_for_status()
# Validate it's actually an image
content_type = resp.headers.get("content-type", "")
if not content_type.startswith("image/"):
print(f" Not an image (content-type: {content_type})", file=sys.stderr)
return False
dest.write_bytes(resp.content)
return True
except requests.RequestException as e:
print(f" Download failed: {e}", file=sys.stderr)
return False
def add_image_field(filepath: Path, slug: str):
"""Add or update the image field in a .cook file."""
url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = filepath.read_text(encoding="utf-8")
if re.search(r"^image:", content, re.MULTILINE):
content = re.sub(r"^image:.*$", f"image: {url}", count=1, flags=re.MULTILINE, string=content)
else:
content = re.sub(r"^---$", f"image: {url}\n---", count=1, flags=re.MULTILINE, string=content)
filepath.write_text(content, encoding="utf-8")
print(f" Updated {filepath.name}", file=sys.stderr)
def search_images(query: str, max_results: int = 5):
"""Search DuckDuckGo Images for a recipe and return image URLs."""
try:
results = list(DDGS().images(query, max_results=max_results))
return [r["image"] for r in results if r.get("image")]
except Exception as e:
print(f" Image search error: {e}", file=sys.stderr)
return []
def get_title(filepath: Path) -> str:
"""Extract title from .cook frontmatter."""
content = filepath.read_text(encoding="utf-8")
match = re.search(r"^title:\s*(.+)$", content, re.MULTILINE)
if match:
return match.group(1).strip()
# Fall back to filename
name = filepath.stem
return name.replace("_", " ").replace("-", " ")
def main():
csv_file = WORKDIR / "docs" / "failed-images.csv"
# Also check which are actually missing
existing_csv = WORKDIR / "docs" / "no-image-has-fm.csv"
recipes = []
with open(existing_csv) as f:
reader = csv.reader(f, delimiter="|")
for row in reader:
if len(row) >= 2:
recipes.append((row[0].strip(), row[1].strip()))
# Filter to those without an image file or without image field
to_process = []
for filename, slug in recipes:
filepath = WORKDIR / filename
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
has_image_file = dest.exists()
has_image_field = False
if filepath.exists():
content = filepath.read_text(encoding="utf-8")
has_image_field = bool(re.search(r"^image:", content, re.MULTILINE))
if not has_image_file or not has_image_field:
to_process.append((filename, slug))
print(f"Processing {len(to_process)} remaining recipes...", file=sys.stderr)
success = []
failed = []
for filename, slug in to_process:
filepath = WORKDIR / filename
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
if not filepath.exists():
failed.append(slug)
continue
title = get_title(filepath)
queries = [
f"{title} recipe",
title,
]
found = False
for query in queries:
print(f"[{slug}] Searching images: {query}", file=sys.stderr)
urls = search_images(query)
for img_url in urls:
# Skip tiny icons, logos
if any(kw in img_url.lower() for kw in ["logo", "icon", "avatar", "merriam", "wikipedia"]):
continue
print(f" Trying: {img_url[:80]}...", file=sys.stderr)
if download_image(img_url, dest):
print(f" Downloaded!", file=sys.stderr)
add_image_field(filepath, slug)
found = True
break
time.sleep(0.2)
if found:
break
time.sleep(0.5)
if found:
success.append(slug)
else:
failed.append(slug)
print(f"\n=== Results ===", file=sys.stderr)
print(f"Success: {len(success)}", file=sys.stderr)
print(f"Failed: {len(failed)}", file=sys.stderr)
if failed:
print(f"Failed: {', '.join(failed)}", file=sys.stderr)
if __name__ == "__main__":
main()
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env python3
"""Add frontmatter and images to 9 recipes without frontmatter."""
import re, sys, time
from pathlib import Path
import requests
from bs4 import BeautifulSoup
from ddgs import DDGS
WORKDIR = Path("/home/jbrechtel/recipes/.worktrees/recipe-images")
HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"}
# (filename, slug, title, source_url_or_empty)
recipes = [
("Black Pepper Tofu (Ottolenghi).cook", "black-pepper-tofu-ottolenghi", "Black Pepper Tofu (Ottolenghi)", ""),
("Black Pepper Tofu with Bok Choy.cook", "black-pepper-tofu-with-bok-choy", "Black Pepper Tofu with Bok Choy", ""),
("butternut-turkey-chili.cook", "butternut-turkey-chili", "Butternut & Turkey Chili", ""),
("Caramel Cake.cook", "caramel-cake", "Caramel Cake", ""),
("Caramel Icing.cook", "caramel-icing", "Caramel Icing", ""),
("example-fried-rice.cook", "example-fried-rice", "Fried Rice", ""),
("indian-spiced-chicken.cook", "indian-spiced-chicken", "Indian Spiced Chicken", ""),
("Italian Sausage and Delicata Rigatoni.cook", "italian-sausage-and-delicata-rigatoni", "Italian Sausage & Delicata Rigatoni", ""),
("shrimp-feta.cook", "shrimp-feta", "Orzo with shrimp, tomato and marinated feta", "https://thehappyfoodie.co.uk/recipes/ottolenghis-orzo-with-prawns-tomato-and-marinated-feta/"),
]
def fetch_og_image(url: str) -> str | None:
try:
resp = requests.get(url, headers=HEADERS, timeout=15)
resp.raise_for_status()
except:
return None
soup = BeautifulSoup(resp.text, "html.parser")
for meta in soup.find_all("meta"):
c = meta.get("content", "")
p = (meta.get("property") or "").lower()
n = (meta.get("name") or "").lower()
if ("og:image" in p or "og:image" in n or "twitter:image" in n) and c:
return c
# JSON-LD
for script in soup.find_all("script", type="application/ld+json"):
try:
import json
data = json.loads(script.string)
items = data if isinstance(data, list) else [data]
for item in items:
if isinstance(item, dict) and item.get("@type") == "Recipe":
img = item.get("image")
if isinstance(img, str): return img
if isinstance(img, list):
for i in img:
if isinstance(i, str): return i
if isinstance(i, dict):
u = i.get("contentUrl") or i.get("url", "")
if u: return u
if isinstance(img, dict):
u = img.get("contentUrl") or img.get("url", "")
if u: return u
except:
pass
return None
def search_and_scrape(query: str) -> str | None:
try:
results = list(DDGS().text(query, max_results=5))
except:
return None
for r in results:
url = r.get("href", "")
if not url or "pinterest" in url or "facebook" in url:
continue
img = fetch_og_image(url)
if img:
return img
time.sleep(0.3)
return None
def download_image(url: str, dest: Path) -> bool:
try:
resp = requests.get(url, headers=HEADERS, timeout=30)
resp.raise_for_status()
ct = resp.headers.get("content-type", "")
if not ct.startswith("image/"):
return False
content = resp.content
if len(content) < 5000:
return False
dest.write_bytes(content)
return True
except:
return False
def add_frontmatter(filepath: Path, slug: str, title: str):
url = f"https://roux.roo.lol/recipe-images/{slug}.webp"
content = filepath.read_text(encoding="utf-8")
frontmatter = f"""---
title: {title}
description:
servings: 1
category: uncategorized
source: Unknown
image: {url}
---
"""
filepath.write_text(frontmatter + content, encoding="utf-8")
print(f" Added frontmatter to {filepath.name}", file=sys.stderr)
def main():
for filename, slug, title, src_url in recipes:
fp = WORKDIR / filename
dest = WORKDIR / "recipe-images" / f"{slug}.webp"
print(f"[{slug}] Processing {filename}", file=sys.stderr)
# Find and download image
img_url = None
if src_url:
print(f" Trying source URL: {src_url}", file=sys.stderr)
img_url = fetch_og_image(src_url)
time.sleep(0.3)
if not img_url:
print(f" Searching: {title} recipe", file=sys.stderr)
img_url = search_and_scrape(f"{title} recipe")
time.sleep(0.3)
if not img_url:
print(f" Searching (alt): {title}", file=sys.stderr)
img_url = search_and_scrape(title)
time.sleep(0.3)
if img_url:
print(f" Found: {img_url[:80]}", file=sys.stderr)
if download_image(img_url, dest):
print(f" Downloaded ({dest.stat().st_size} bytes)", file=sys.stderr)
else:
print(f" Download failed, will still add frontmatter", file=sys.stderr)
else:
print(f" No image found, will still add frontmatter", file=sys.stderr)
# Add frontmatter (with or without image)
add_frontmatter(fp, slug, title)
print(f" Done", file=sys.stderr)
print("\n=== Task 3 complete ===", file=sys.stderr)
if __name__ == "__main__":
main()
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
while IFS='|' read -r file slug; do
new_url="https://roux.roo.lol/recipe-images/$slug.webp"
sed -i "s|^image:.*|image: $new_url|" "$file"
echo "[$slug] Updated image field"
done
+45
View File
@@ -0,0 +1,45 @@
---
title: Blackened Sheet Pan Salmon
subtitle: with spring onions, potatoes, carrots & buttermilk-herb drizzle
author: Chef Torie Cox
servings: 2
prep time: 20 minutes
cook time: 35 minutes
time: 35 minutes
allergens: [fish, dairy, egg]
source: /recipe-images/Scan_20260527_173752.jpg
image: /recipe-images/blackened-sheet-pan-salmon.jpg
------
== Cook Veggies ==
Preheat oven to 425°F.
Dice @potatoes{2%cups} into 1/2" pieces.
Trim root and slice bulb of @spring onion{1}, then chop green tops into 1" pieces.
Zest HALF of @lemon{1} [- whole lemon for meal kits serving 4 -], cut remainder into wedges for garnish.
On a #sheet pan{}, toss @potatoes{}, @carrot coins{6%oz}, @spring onion{} bulb & tops with HALF of @thyme sprigs{1%tsp}, @oil{2%tbsp} [- 3 tbsp -], @salt{} & @pepper{}, then spread veggies out in an even layer [- use a second sheet pan if necessary -] and roast for ~{15%minutes}.
== Make Sauce ==
Pick leaves from remaining @thyme{} and chop.
Chop @chives{} & @dill{}.
In a #bowl{}, whisk together @Buttermilk Sauce Starter{2%tbsp}(buttermilk), @mayonnaise{2%tbsp}, @grainy dijon mustard{1/4%tsp}, @Creole seasoning{1/2%tsp}, chopped herbs and lemon zest.
== Cook Salmon ==
Pat @salmon fillets{2} dry, then season with @Creole seasoning{1%tsp}.
After veggies have been roasting for ~{15%minutes}, toss, then place @salmon{} skin-side down next to the veggies.
Cut @butter{1%tbsp} [- 2 tbsp -] into small cubes, dot salmon with butter, then bake ~{8-12%minutes}, until salmon is done and veggies are tender.
== Garnish & Gather ==
Divide veggies among plates and top with salmon. Serve with buttermilk sauce for drizzling and garnish with lemon wedges.
@@ -0,0 +1,18 @@
---
title: Bridget Jones's Pan-Fried Salmon with Pine Nut Salsa
source: Simple - Ottolenghi
description: A vibrant pan-fried salmon with a sweet and savoury pine nut salsa featuring currants, capers, olives, and saffron.
servings: 4 servings
tags: Pan-Fried, Seafood, Salmon, Dinner, Fish
image: /recipe-images/bridget-jones-s-pan-fried-salmon-with-pine-nut-salsa.jpg
---
Cover @currants{3/4%cup} with boiling water and set aside to soak for ~{20%minutes} while you prep the salmon and make the salsa.
Mix @salmon fillets{4}(skin on and pinbones removed) with 1 tbsp of the @olive oil{7%tbsp}{1%tbsp}, a rounded ¼ tsp salt, and a good grind of @black pepper{}. Set aside while you make the salsa.
Put 5 tbsp of the @olive oil{7%tbsp}{5%tbsp} into a #large sauté pan{} and place on a high heat. Add @celery stalks{4}(medium, cut into 1/2-inch dice, leaves kept for garnish) and @pine nuts{1/4%cup}(roughly chopped) and fry for ~{4-5%minutes}, stirring frequently, until the nuts begin to brown (don't take your eyes off them, as they can easily burn). Remove the pan from the heat and stir in @capers{1/4%cup}(plus 2 tbsp of their brine), @green olives{1/3%cup}(large, pitted and cut into 1/2-inch dice), @saffron threads{1%good pinch}(mixed with 1 tbsp hot water) and its water, and a pinch of @salt{}. Drain the currants and add these, along with @parsley{1%cup}(roughly chopped), lemon zest from @lemon{1}, and lemon juice from @lemon{}. Set aside.
Put the remaining 1 tbsp of @olive oil{7%tbsp}{1%tbsp} into a #large frying pan{} and place over medium-high heat. Once hot, add the @salmon fillets{}, skin side down, and fry for ~{3%minutes}, until the skin is crisp. Decrease the heat to medium, then flip the fillets over and continue to fry for ~{2-4%minutes} (depending on how much you like the salmon cooked). Remove from the pan and set aside.
Arrange the salmon on four plates and spoon on the salsa. Scatter the reserved celery leaves on top.
+55
View File
@@ -0,0 +1,55 @@
---
title: Butternut & Turkey Chili
subtitle: with white beans, spiced pepitas & queso fresco
author: Chef Torie Cox
servings: 2
time: 40 minutes
prep time: 20 minutes
tags:
- meat
- turkey
- chili
- soup
- fall
diet:
- gluten-free
description: A hearty chili with butternut squash, ground turkey, white beans, and spiced pepitas topped with queso fresco.
category: dinner
image: https://roux.roo.lol/recipe-images/butternut--turkey-chili.webp
---
== Toast Pepitas & Prep Veggies ==
In a #pot large enough to cook the chili in later{}, heat @olive oil{1%tbsp} over med heat.
Add @pepitas{1/4%cup}, @smoked paprika{1/4%tsp}, @cayenne{1/8%tsp}, @cinnamon{1/8%tsp} and a pinch of @salt{}.
Toast, stirring frequently, until @pepitas{} smell fragrant and are lightly browned, ~{3-5%minutes}, then remove from #pot and set aside.
Remove seeds and chop @poblano pepper{3/4%cup}.
Chop @cilantro{2%tbsp}.
Drain and rinse @cannellini beans{1,1/2%cups}.
Cut @lime{1} into wedges.
== Prep & Cook Chili ==
In the same #pot used for pepitas{}, heat @olive oil{2%tbsp} over med-high heat.
Add @ground turkey{8%oz} and @salt{1/4%tsp} and @pepper{1/4%tsp} and cook ~{5-8%minutes}, until browned, breaking up with a #wooden spoon, then remove.
To the same #pot, add @butternut squash{1,1/2%cups}(diced), @onion{2%tbsp}, @garlic{1%tbsp} and @poblano pepper{} and cook until beginning to soften, ~{5-7%minutes}.
Add @chili powder{1%tbsp}, @cumin{2%tsp}, @smoked paprika{1%tsp}, @dried oregano{1/2%tsp}, and @cayenne{1/2%tsp} and cook ~{1%minute} or until fragrant. > HOT! add cayenne to taste.
Stir in @chicken broth{1/2%cup}, @crushed tomatoes{1%cup}, @water{1/2%cup}, cooked @turkey{}, @beans{} and @salt{1/2%tsp}, bring to a boil, then reduce heat to low and cook until @butternut squash{} is tender, ~{20%minutes}.
Crumble @queso fresco{2%tbsp}.
Adjust chili seasoning to taste.
== Garnish & Gather ==
Serve chili in #bowls topped with spiced @pepitas{}, @sour cream{3%tbsp}, @queso fresco{}, @cilantro{} and @lime wedges{}.
-47
View File
@@ -1,47 +0,0 @@
>> title: Butternut & Turkey Chili
>> author: Chef Torie Cox
>> servings: 2
>> totalTime: 40 minutes
>> tags: chili, turkey, butternut squash
# Toast pepitas & prep veggies
In a large #pot heat 1 tbsp @olive oil over medium heat.
Add 1/4 cup @pepitas, 1/4 tsp @smoked paprika, 1/8 tsp @cayenne, 1/8 tsp @cinnamon, and a pinch of @salt.
Toast, stirring frequently, until fragrant and lightly browned, about ~3-5 minutes.
Transfer pepitas to a #bowl and set aside.
Remove seeds from 3/4 cup @sweet pepper and chop.
Finely chop 2 tbsp @onion and 1 tbsp @garlic if not prepped.
Chop 2 tbsp @cilantro.
Drain and rinse 1 cup @cannellini beans.
Cut 1 @lime into wedges.
---
# Prep & cook chili
In the same #pot heat 2 tbsp @olive oil over medium-high heat.
Add 8 oz @ground turkey and season with 1/4 tsp @salt and 1/4 tsp @black pepper.
Cook, breaking up with a #wooden spoon, until browned, about ~5-8 minutes.
Remove turkey from pot and set aside.
To the #pot add 1 1/2 cups @butternut squash (diced), 2 tbsp @onion (if not already in), 1 tbsp @garlic (if not already in), and the chopped @sweet pepper.
Cook, stirring occasionally, until beginning to soften, about ~5-7 minutes.
Add 1 tsp @chili powder, 2 tsp @cumin, 1 tsp @smoked paprika, and 1/4 tsp @dried oregano.
Cook until fragrant, about ~1 minute.
Stir in 1 container @crushed tomatoes, 1/2 cup @chicken broth, 1/2 cup @water, the cooked @ground turkey, the drained @cannellini beans, and 1/2 tsp @salt.
Bring to a boil, then reduce heat to low and simmer until butternut is tender, about ~20 minutes.
Taste and adjust seasoning with additional @salt and @black pepper.
Crumble 2 tbsp @queso fresco in a small #bowl.
---
# Garnish & serve
Ladle chili into #bowls.
Top each serving with spiced @pepitas, 3 tbsp @sour cream, crumbled @queso fresco, chopped @cilantro, and @lime wedges.
Serve hot.
@@ -0,0 +1,42 @@
---
title: Cajun Butter Mahi with Corn & Okra Maque Choux over Carolina Gold Rice
servings: 2
prep time: 30 minutes
time: 45 minutes
author: Chef Torie Cox
cuisine: Cajun
tags:
- fish
- seafood
- rice
description: Cajun-seasoned mahi mahi served with a corn and okra maque choux over Carolina Gold rice, drizzled with a Cajun butter sauce.
source: /recipe-images/document_1_.pdf
------
== Cook Rice ==
In a #pot, heat @oil{1%tbsp} over medium heat. Add @Carolina Gold rice{3/4%cup} and stir to toast for ~{2%minutes}.
Add @water{1,1/4%cups} and @salt{} and bring to a boil, then reduce heat to low, cover and cook for ~{15%minutes}. Remove from heat and let stand for ~{10%minutes}.
== Cook Maque Choux & Make Cajun Butter ==
Slice @okra{1%cup} into 1/4" thick rounds. Remove core and cut @sweet pepper{1%cup} into 1/2" dice. Cut corn kernels from the cobs of @corn{2%ears}. Slice @scallion{1}.
In a #large sauté pan{} over medium heat, add @oil{1%tbsp}, the diced pepper and @onion{1/2%cup} and cook for ~{5%minutes} or until beginning to soften.
Add the corn, okra and half of the @garlic{1,1/2%tsp}, cook for ~{5-7%minutes} until tender, then season with @salt{} and @pepper{}. Remove to a #bowl and wipe out the pan.
Melt @butter{1%oz} in a #small bowl{} in the microwave, then stir in half of the @Cajun seasoning{1%tbsp}, the remaining garlic, and salt. -- this is the Cajun butter sauce
== Cook Fish ==
In the same #sauté pan{}, heat @oil{1%tbsp} over medium-high heat. Pat the @mahi mahi fillets{2} dry and season with the remaining Cajun seasoning, @salt{}, and @pepper{}.
Add the fish to the hot pan and cook ~{2-3%minutes} per side, or until desired doneness.
Add the sliced scallion to the rice and fluff with a fork.
== Garnish & Serve ==
Divide the fish, rice, and maque choux among plates, then drizzle with the Cajun butter sauce.
+26
View File
@@ -0,0 +1,26 @@
---
title: Carbonara
source: //cooking.nytimes.com/recipes/12965-spaghetti-carbonara
description: This dish is a deli bacon-egg-and-cheese-on-a-roll that has been pasta-fied, fancified, fetishized and turned into an Italian tradition that, like many inviolate Italian traditions, is actually far less old than the Mayflower. Because America may have contributed to its creation, carbonara is Exhibit A in the back-and-forth between Italy and the United States when it comes to food. Remember: the main goal is creaminess.
author: Ian Fisher
course: Dinner, Main Course, Pastas
cuisine: Italian
servings: 4 servings
totalTime: 30 minutes
prepTime: 5 minutes
cookTime: 25 minutes
tags: Bacon, Cheese, Easy, Egg, Five Ingredient, Pancetta, Quick, Spaghetti
---
== Ingredients ==
, @large eggs and 2 large yolks{2}, @(about ⅓ packed cup) grated pecorino Romano{1%ounce}, @(about ⅓ packed cup) grated Parmesan{1%ounce}, @Coarsely ground black pepper, @olive oil{1%tablespoon}, @½ ounces of slab guanciale (see recipe){3}, @spaghetti (about ¾ box){12%ounces}
== Method ==
Place a large pot of lightly salted water (no more than 1 tablespoon salt) over high heat, and bring to a boil. Fill a large bowl with hot water (to warm the bowl for serving), and set aside.
In a mixing bowl, whisk together the eggs, yolks and pecorino and Parmesan. Season with a pinch of salt and generous black pepper.
Set the water to boil. Meanwhile, heat oil in a large skillet over medium heat, add the pork, and sauté until the fat just renders, on the edge of crispness but not hard. Remove from heat and set aside.
Add pasta to the water and boil until a bit firmer than al dente. Just before pasta is ready, reheat guanciale in skillet, if needed. Reserve 1 cup of pasta water, then drain pasta and add to the skillet over low heat. Stir for a minute or so.
Empty serving bowl of hot water. Dry it and add hot pasta mixture. Stir in cheese mixture, adding some reserved pasta water if needed for creaminess. Serve immediately, dressing it with a bit of additional grated pecorino and pepper.
+554
View File
@@ -0,0 +1,554 @@
{
"@context": "https://schema.org",
"@id": "urn:nyt:ScoopRecipe:c32379cbd70d591f9932fec6ad7497ce",
"@type": "Recipe",
"aggregateRating": {
"@type": "AggregateRating",
"ratingCount": 17150,
"ratingValue": 5
},
"alternateName": "Spaghetti Carbonara",
"author": {
"@id": "nyt://person/4c04b52b-86cf-5da4-8a5a-2142526e3e16",
"@type": "Person",
"description": "Ian Fisher worked for The New York Times from 1990 to 2017, reporting from nearly 60 countries and serving as bureau chief in East Africa, Eastern Europe, Rome and Jerusalem. He later returned to New York, where he served as deputy foreign editor, as a masthead editor in charge of The Timess digital transition, as head of investigations, and as weekend editor. His final role at The Times was Jerusalem bureau chief.",
"image": {
"@id": "nyt://image/f8d237e1-0aab-5e9a-8de4-db3fd3b20b91#mediumSquareAt3X",
"@type": "ImageObject",
"contentUrl": "https://static01.nyt.com/images/2026/03/24/reader-center/author-ian-fisher/author-ian-fisher-mediumSquareAt3X.png",
"dateModified": "2026-03-24T14:49:22.379Z",
"datePublished": "2026-03-24T14:49:22.379Z",
"height": "1000",
"uploadDate": "2026-03-24T14:49:22.379Z",
"url": "https://static01.nyt.com/images/2026/03/24/reader-center/author-ian-fisher/author-ian-fisher-mediumSquareAt3X.png",
"width": "1000"
},
"name": "Ian Fisher",
"sameAs": [
"https://x.com/fisheri",
"https://www.facebook.com/ian.fisher.5661"
],
"url": "https://www.nytimes.com/by/ian-fisher"
},
"cookTime": "PT0H25M",
"cookingMethod": "Boil, Saute",
"copyrightHolder": {
"@id": "https://cooking.nytimes.com/#publisher",
"@type": "Organization",
"name": "NYT Cooking"
},
"copyrightYear": 2012,
"dateModified": "2026-04-06T17:54:34.901Z",
"datePublished": "2012-11-21T00:00:00Z",
"description": "This dish is a deli bacon-egg-and-cheese-on-a-roll that has been pasta-fied, fancified, fetishized and turned into an Italian tradition that, like many inviolate Italian traditions, is actually far less old than the Mayflower. Because America may have contributed to its creation, carbonara is Exhibit A in the back-and-forth between Italy and the United States when it comes to food. Remember: the main goal is creaminess.",
"image": [
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#videoSixteenByNineJumbo1600",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-videoSixteenByNineJumbo1600-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "899",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-videoSixteenByNineJumbo1600-v2.jpg",
"width": "1600"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#googleFourByThree",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-googleFourByThree-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "600",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-googleFourByThree-v2.jpg",
"width": "800"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#mediumSquareAt3X",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-mediumSquareAt3X-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "1417",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-mediumSquareAt3X-v2.jpg",
"width": "1419"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#facebookJumbo",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-facebookJumbo-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "549",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-facebookJumbo-v2.jpg",
"width": "1050"
}
],
"isAccessibleForFree": true,
"keywords": "Bacon, Cheese, Easy, Egg, Five Ingredient, Pancetta, Quick, Spaghetti",
"mainEntityOfPage": {
"@id": "//cooking.nytimes.com/recipes/12965-spaghetti-carbonara",
"@type": "WebPage",
"name": "Carbonara"
},
"name": "Carbonara",
"nutrition": {
"@type": "NutritionInformation",
"calories": "534.5 kcals",
"carbohydrateContent": "64.4 grams",
"cholesterolContent": "121.6 milligrams",
"fatContent": "19.9 grams",
"fiberContent": "2.8 grams",
"proteinContent": "22.4 grams",
"saturatedFatContent": "6.9 grams",
"sodiumContent": "412 milligrams",
"sugarContent": "2.5 grams",
"unsaturatedFatContent": "2.8 grams"
},
"prepTime": "PT0H5M",
"publisher": {
"@id": "https://cooking.nytimes.com/#publisher",
"@type": "Organization",
"name": "NYT Cooking"
},
"recipeCategory": "Dinner, Main Course, Pastas",
"recipeCuisine": "Italian",
"recipeIngredient": [
"Salt ",
"2 large eggs and 2 large yolks, room temperature ",
"1 ounce (about ⅓ packed cup) grated pecorino Romano, plus additional for serving ",
"1 ounce (about ⅓ packed cup) grated Parmesan ",
"Coarsely ground black pepper ",
"1 tablespoon olive oil ",
"3 ½ ounces of slab guanciale (see recipe), pancetta or bacon, sliced into pieces about ¼ inch thick by 1⅓ inch square ",
"12 ounces spaghetti (about ¾ box) "
],
"recipeInstructions": [
{
"@type": "HowToStep",
"text": "Place a large pot of lightly salted water (no more than 1 tablespoon salt) over high heat, and bring to a boil. Fill a large bowl with hot water (to warm the bowl for serving), and set aside.",
"url": "https://cooking.nytimes.com/recipes/12965-spaghetti-carbonara#recipe-step-1"
},
{
"@type": "HowToStep",
"text": "In a mixing bowl, whisk together the eggs, yolks and pecorino and Parmesan. Season with a pinch of salt and generous black pepper.",
"url": "https://cooking.nytimes.com/recipes/12965-spaghetti-carbonara#recipe-step-2"
},
{
"@type": "HowToStep",
"text": "Set the water to boil. Meanwhile, heat oil in a large skillet over medium heat, add the pork, and sauté until the fat just renders, on the edge of crispness but not hard. Remove from heat and set aside.",
"url": "https://cooking.nytimes.com/recipes/12965-spaghetti-carbonara#recipe-step-3"
},
{
"@type": "HowToStep",
"text": "Add pasta to the water and boil until a bit firmer than al dente. Just before pasta is ready, reheat guanciale in skillet, if needed. Reserve 1 cup of pasta water, then drain pasta and add to the skillet over low heat. Stir for a minute or so.",
"url": "https://cooking.nytimes.com/recipes/12965-spaghetti-carbonara#recipe-step-4"
},
{
"@type": "HowToStep",
"text": "Empty serving bowl of hot water. Dry it and add hot pasta mixture. Stir in cheese mixture, adding some reserved pasta water if needed for creaminess. Serve immediately, dressing it with a bit of additional grated pecorino and pepper.",
"url": "https://cooking.nytimes.com/recipes/12965-spaghetti-carbonara#recipe-step-5"
}
],
"recipeYield": "4 servings",
"review": [
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "ELBSeattle"
},
"datePublished": "2026-06-14T02:42:35.000Z",
"reviewBody": "About the garlic debate: if you like garlic, add it. If you dont, dont. I think 100% authenticity would only matter if this dish were being made in a competition, for a grade in a culinary school or if one is a chef at an Italian restaurant. Otherwise, I think it is 100% fine to color outside if the lines when cooking fir ones self, family and friends. (My version of gâteau basque has a very inauthentic layer of coconut cream, and no one has complained.)"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Tea Totaler Adjacent"
},
"datePublished": "2026-06-13T17:48:33.000Z",
"reviewBody": "I use Fontinella instead of Romano. Very hard to find though."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Richard X"
},
"datePublished": "2026-06-13T21:33:07.000Z",
"reviewBody": "My family prefers a portion size of about 4 oz. We don't \"look at packages\" for dining tips."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Rick Davidson"
},
"datePublished": "2026-06-13T16:37:51.000Z",
"reviewBody": "Look at the package. A single portion of pasta is 2-2.5 oz."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Pat"
},
"datePublished": "2026-06-13T05:34:10.000Z",
"reviewBody": "you need to temper a bit of the egg and cheese mixture into the pasta rather than dumping it in all at once- otherwise you will have scrambled eggs. I have also started using Trader Joes pancetta for an easier to make dish, topped with parsley to finish"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Barbara"
},
"datePublished": "2026-06-13T03:38:24.000Z",
"reviewBody": "PLEASE! NO CREAM!"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Richard X"
},
"datePublished": "2026-06-13T12:27:09.000Z",
"reviewBody": "The water that was in the bowl has now cooled a bit, and we don't want that. A quick wipe of the bowl is not a burdensome step. Nit-picky indeed."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Equilibrist"
},
"datePublished": "2026-06-13T00:00:57.000Z",
"reviewBody": "This is nit-picky, I know, but why would you dry the bowl that has had hot water in it before adding a pasta and pork mix that is just going to have more water added? I guess I just like it when recipes are streamlined, and this adds a completely unnecessary step."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Susan"
},
"datePublished": "2026-06-12T22:52:52.000Z",
"reviewBody": "Good tips on how not to make \"scrambled egg\" pasta."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Showsomebackbone"
},
"datePublished": "2026-06-12T22:02:38.000Z",
"reviewBody": "Huh! Guanciale looks a lot like salt pork lol. Goes to show similarities in foods across cultures/countries. \nHas anyone ever included sautéed (in the bacon fat), diced, sweet onion?"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Bailey"
},
"datePublished": "2026-06-12T22:31:27.000Z",
"reviewBody": "Considering what a disaster getting ingredients to make this ended up being (for context I made this at 6pm, my almost 3 year old happily playing, so I could not leave to fix the errors) when I asked someone to grab the few things I didnt already have on hand (the cheese, and bacon) and ended up with pre cooked bacon (why 😭) and the powdered cheese you get in a green bottle\n(Double why), I still made this dish and it ended up being very good! Will definitely\nMake again with the proper ingredients, but even without, this one gets 5 stars!"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Pete E. Pye"
},
"datePublished": "2026-06-12T20:11:55.000Z",
"reviewBody": "This recipe is fine as is, and the tips below are excellent. I add a 1/2 cup of white wine at the step where I reheat the pancetta, to deglaze the pan and also cause ya know, wine."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Richard"
},
"datePublished": "2026-06-14T09:19:10.000Z",
"reviewBody": "Every recipe should \"triple the garlic.\" Ask any NYT Cooking readers."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Lisa"
},
"datePublished": "2026-06-12T19:22:48.000Z",
"reviewBody": "Spaghetti carbonara does not have garlic in it. Ask any Italian."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Rockothecat"
},
"datePublished": "2026-06-12T17:38:59.000Z",
"reviewBody": "My father severed in the US Army during WWII from Napoli, Roma, Southern France and the Rhineland. He learned to speak Italian, while there and he talked about a dish the locals made for the US solders, pasta alla carbonara, with bacon, egg and cheese, to remind the soldiers of an American breakfast they would have had back home,\nAfter the war, my father went to college on the GI bill, got a Masters in Agricultural Economics and was posted to the US Embassy in Rome in 1958 where I was born."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "rockothecatcat"
},
"datePublished": "2026-06-12T17:52:33.000Z",
"reviewBody": "While in Roma,1958, my mother learned a local recipe for pasta alla carbonara: slab cured pork, egg, diced onion, parsley, Parmesan cheese, pepper, red wine. I use thick cut bacon. How to: bacon and onion saute till light brown, pour off excess fat, set aside, boil spaghetti al dente, in a bowl, beat one egg, add copped parsley, fresh ground pepper, set aside. Heat up pan again, use red wine to deglaze. Place hot drained spaghetti in bowl, mix, add deglaze bacon/onion, sprinkle cheese, serve."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Kevin"
},
"datePublished": "2026-06-12T17:30:31.000Z",
"reviewBody": "Toss the hot pasta in the bowl with the egg and cheese mixture. Then stir in the cooked guanciale or pancetta."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "ken"
},
"datePublished": "2026-06-12T17:35:59.000Z",
"reviewBody": "I prefer to use a large plastic mixing bowl or salad bowl to beat the eggs and cheese. If you mix the pasta into that the pasta will stay warmer than if you use a metal or ceramic bowl (even if you warm the bowl). Heat the individual pasta bowls. Cold carbonara is an abomination, or at least a different dish."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Julian Fernandez"
},
"datePublished": "2017-10-30T15:18:00.000Z",
"reviewBody": "Never combine the ingredients in the pan you have had on the burner. The eggs will cook and harden. Place a stainless steel mixing bowl under your colander and let the pasta water heat the bowl. Discard the water and use the heated bowl to combine all ingredients. Toss for at least two minutes."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Julian Fernandez"
},
"datePublished": "2017-10-30T15:20:22.000Z",
"reviewBody": "At Step 2, a clove or two of minced or pressed garlic should be added to the egg and cheese mixture. I've never seen a carbonara recipe that did not include garlic.<br/><br/>At Step 3, you can replace the olive oil with 1/4 C. water. Sounds crazy, but the bacon will remain tender and flavorful. After it has cooled slightly, whisk one or two tablespoons of rendered bacon fat, in a slow stream, into the egg/cheese/garlic mixture. Much creamier and flavorful."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Max H."
},
"datePublished": "2017-10-24T15:12:50.000Z",
"reviewBody": "This recipe is spot on. My wife thinks I'm a pro when I cook it :) I do have 1 tip though. Don't be afraid to add the starchy water at the end. Doing so makes it more smoothy and creamy. It might seem a little too wet at first but it will cool down and be just right. The first 2 times I made this dish I only added a 1/4 cup of water because it looked wet enough. However once the dish cooled it got a bit sticky and dry. I regretted not adding more water and learned my lesson."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Alexa H"
},
"datePublished": "2017-10-30T15:51:39.000Z",
"reviewBody": "Just of interest, where is the garlic that is mentioned so frequently in the reviews? In eating Roman spaghetti carbonara there was absolutely no garlic. Much food in Italy has very spare amounts of or even no garlic. It is in America that we add so much garlic to Italian food."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Mark"
},
"datePublished": "2017-10-24T17:24:51.000Z",
"reviewBody": "Good version of carbonara. I generally buy pasteurized eggs when I make this. I prefer all yolks rather than whole eggs. I don't generally buy pecorino, so I use all parmesan. If you use bacon, don't get anything too heavily smoked. I generally use bacon because pancetta is triple the cost and guanciale is even more costly. And for goodness sake, why on earth would anybody create a recipe for 3/4 lb pasta. Toss in another egg and a few additional slices of bacon."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Steve Muni"
},
"datePublished": "2017-10-24T19:47:24.000Z",
"reviewBody": "I also saute half a chopped onion with the pancetta, and add half a cup of chopped parsley at the very end. That's the way I was taught by my mother, who learned it from the cook at a little Rome trattoria in 1951."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Cheryl"
},
"datePublished": "2017-10-30T15:55:20.000Z",
"reviewBody": "Regardless of whether it should have garlic or shouldn't, whether cream negates it as carbonara or not, whether eggs are necessary (um, yes), this is delicious. I went on a carbonara kick a few weeks ago, and I've tried out eleven recipes so far, and this is my favorite by far for its ease and quickness."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "kate"
},
"datePublished": "2017-10-01T19:30:36.000Z",
"reviewBody": "You need to add the HOT pasta to the egg/cheese mixture to slightly/lightly cook it, and to coat the pasta with the \"creamy\" mixture. If you had pasta to bacon grease FIRST, the egg/cheese mixture will not adhere to the pasta, and you will end up with a lumpy mess in the bottom of the bowl-- it will slide off the pasta.<br/>Speaking as someone who grew up in Rome, (a) capitol of Carbonara."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Paolo"
},
"datePublished": "2017-10-01T19:29:04.000Z",
"reviewBody": "Recipes are guidelines people! If the end result is good, who cares if it doesn't conform exactly to what your grandmother did. More than likely her version varied depending on what was around. I can't believe people become angry over varieties of grated cheese."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Publius"
},
"datePublished": "2017-10-24T18:43:15.000Z",
"reviewBody": "NO!!! No garlic!!!!"
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Elisabeth P"
},
"datePublished": "2017-10-30T15:51:07.000Z",
"reviewBody": "Beat whole eggs (2 @ person?) in pasta bowl, add some olive oil or butter. Cook bacon pieces/pancetta, drain on paper towels; cook sliced onion & garlic, add bacon back in, add white wine or dry vermouth. Cook spaghetti, then spoon some hot pasta water into eggs, stirring, then using tongs put all hot spaghetti into eggs quickly, let sit two seconds, toss. Toss in bacon mixture, seasonings (parsley, oregano, hot pepper flakes?), more pasta water if dry, serve with grated pecorino."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "PTFogarty"
},
"datePublished": "2017-10-30T15:49:41.000Z",
"reviewBody": "Thank you for not including cream or milk, as many \"so called\" carbonara recipes do. Cream makes it Alfredo. I fell in love with carbonara when I was stationed in Naples, Italy, with the US Navy. In my version, I only use Parmesan, not Romano, but often add a bit of garlic to the frying bacon.<br/><br/>And yes, eggs are necessary. The dish was invented at the end of WWII when Napolitans discovered the GI's powered eggs."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Patrizia"
},
"datePublished": "2017-10-01T15:28:38.000Z",
"reviewBody": "I've lived in Rome. Never had a Carbonara made with garlic. I do like the version with onions,though. Authentic Roman Carbonara is always made with guanciale. We definitely dribbled the guanicale fat in with the egg mixture. Produces that gorgeously sensual lip slicking as you fork the twirled pasta into your mouth. I especially love carbonara with lots of coarse ground pepper--the 'carbon' of the recipe."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "Joe B."
},
"datePublished": "2017-10-30T14:48:37.000Z",
"reviewBody": "Well, I suppose you could use eggbeaters. But then again, you could substitute smoked ham, Velveeta and noodles for the other three ingredients and get an acceptable dinner. It just wouldn't be Spaghetti Carbonara."
},
{
"@type": "Review",
"author": {
"@type": "Person",
"name": "greg b"
},
"datePublished": "2017-10-24T18:52:51.000Z",
"reviewBody": "I made pork belly and had some leftover. I thought, \"why not make carbonara?\".<br/><br/>First, I used a wide noodle, parpardelle, and all of cheese was parmesan, but otherwise I followed this recipe to a tee as I've always made it that way.<br/><br/>The pork belly, sliced into lardons about 3 cm x 1 cm, were substituted for the bacon.<br/><br/>Mind blown...oh my goodness, this was the BEST version of this dish I have ever made or tasted."
}
],
"totalTime": "PT0H30M",
"url": "//cooking.nytimes.com/recipes/12965-spaghetti-carbonara",
"video": {
"@id": "nyt://video/6204b9e9-efa5-5ef5-94a5-28ccede9a986",
"@type": "VideoObject",
"author": {
"@id": "nyt://person/86245e1a-0c21-50e7-943b-64a772deff66",
"@type": "Person",
"name": "Anne Alexander",
"url": "https://www.nytimes.com/by/anne-alexander"
},
"bitrate": "0",
"contentSize": "18773866",
"contentUrl": "https://vp.nyt.com/video/2017/06/23/73101_1_recipe-carbonara_wg_480p.mp4",
"dateModified": "2024-10-15T20:14:16.185Z",
"datePublished": "2017-06-29T15:59:30.000Z",
"description": "How to make a perfect version of this classic pasta.",
"duration": "PT1M35S",
"height": "480",
"name": "Spaghetti Carbonara",
"publisher": {
"@id": "https://www.nytimes.com/#publisher",
"@type": "NewsMediaOrganization",
"name": "The New York Times"
},
"thumbnail": [
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#videoSixteenByNineJumbo1600",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-videoSixteenByNineJumbo1600-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "899",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-videoSixteenByNineJumbo1600-v2.jpg",
"width": "1600"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#googleFourByThree",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-googleFourByThree-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "600",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-googleFourByThree-v2.jpg",
"width": "800"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#mediumSquareAt3X",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-mediumSquareAt3X-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "1417",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-mediumSquareAt3X-v2.jpg",
"width": "1419"
},
{
"@id": "nyt://image/9458a0d9-8671-5969-9f6b-e4ee4d51b701#facebookJumbo",
"@type": "ImageObject",
"caption": "Ian Fisher's spaghetti carbonara.",
"contentUrl": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-facebookJumbo-v2.jpg",
"creditText": "Linda Xiao for The New York Times. Food Stylist: Sarah Jampel.",
"dateModified": "2025-01-21T21:27:32.236Z",
"datePublished": "2018-08-10T20:21:25.000Z",
"height": "549",
"uploadDate": "2018-08-10T20:21:25.000Z",
"url": "https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-facebookJumbo-v2.jpg",
"width": "1050"
}
],
"thumbnailUrl": [
"https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-videoSixteenByNineJumbo1600-v2.jpg",
"https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-googleFourByThree-v2.jpg",
"https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-mediumSquareAt3X-v2.jpg",
"https://static01.nyt.com/images/2021/02/14/dining/carbonara-horizontal/carbonara-horizontal-facebookJumbo-v2.jpg"
],
"transcript": "WG in master proj folder 73033",
"uploadDate": "2017-06-29T15:59:30.000Z",
"url": "https://www.nytimes.com/video/embedded/dining/100000005183614/spaghetti-carbonara.html",
"width": "854"
}
}
+5 -1
View File
@@ -9,7 +9,11 @@ servings: 6 servings
totalTime: 55 minutes
prepTime: 15 minutes
cookTime: 40 minutes
tags: arugula, bread crumb, budget, cauliflower, parmesan, sheet-pan, fall, vegetarian
tags:
- vegetarian
- italian
- vegetable
image: https://roux.roo.lol/recipe-images/cauliflower-milanese.webp
---
== Ingredients ==
@@ -0,0 +1,48 @@
---
title: Chicken & Peach Chimichurri with Summer Squash Fritters
servings: 2
prep time: 35 minutes
time: 50 minutes
author: Chef Robin Pridgen
description: Chicken breasts with a fresh peach chimichurri and homemade summer squash fritters.
tags:
- chicken
- summer
- fritters
source: /recipe-images/document.pdf
image: /recipe-images/chicken--peach-chimichurri-with-summer-squash-fritters.jpg
------
== Prep Veggies & Cook Squash ==
Dice @summer squash{1,1/4%cup}(diced into 1/4" pieces) and thinly slice @green onion{1}.
In a #large nonstick sauté pan{}, heat @olive oil{1%tbsp} over med-high. Add the squash and @salt{} and sauté for ~{4-5%minutes} until softened, then remove, set aside to cool slightly, and wipe out the pan.
== Make Chimichurri ==
Remove the pit and dice @peach{1}(diced into 1/4" pieces). Remove seeds and mince half of @jalapeño{1/2}(minced) — save remainder for another use, or use all for more heat.
Chop @cilantro{2%tbsp} and @parsley{2%tbsp} together.
In a #medium bowl{}, combine the herbs, @red wine vinegar{1,1/2%tbsp}, @garlic{1/2%tsp}, jalapeño to taste, and @olive oil{3%tbsp}. Stir in the diced peach and season to taste with @salt{} and @pepper{}.
== Cook Chicken ==
In the same #large nonstick sauté pan{} used for squash, heat @olive oil{1%tbsp} over med-high. Pat @chicken breasts{2} dry and season with @salt{} and @pepper{}.
Add chicken to the pan and cook ~{6-9%minutes} per side, or until done. Remove, wipe out the pan, and keep warm.
== Make Batter & Cook Fritters ==
Line a #plate with a paper towel.
In a #large mixing bowl{}, mix @egg{1}, @olive oil{2%tbsp}, and @water{1/3%cup}. Add the Fritter Starter — @cornmeal{3/4%cup}, @flour{1/2%cup}, @sugar{2%tsp}, @baking powder{1%tsp}, and @table salt{1%tsp} — and stir to combine. Stir in the cooked squash and sliced green onion.
In the same #large nonstick sauté pan{} used for the chicken, heat @olive oil{2%tbsp} over medium. Scoop 1/4 cup batter into the heated oil to form fritters and cook ~{3-4%minutes} per side, working in batches and adding more oil as needed. Transfer to the paper-towel-lined plate.
Slice the cooked chicken.
== Garnish & Gather ==
Divide the squash fritters and sliced chicken between plates, then drizzle generously with the peach chimichurri.
+60
View File
@@ -0,0 +1,60 @@
---
title: Chicken Piccata
author: Chef Torie Cox
servings: 2
time: 35 minutes
prep time: 25 minutes
cook time: 35 minutes
description: With buttery angel hair pasta & dressed greens with parmesan
diet:
- contains dairy
- contains wheat
- contains egg
source: /recipe-images/Scan_20260525_200616.jpg
image: /recipe-images/chicken-piccata.png
------
== Make Piccata ==
Bring a #pot of salted @water to a boil for pasta.
Butterfly @chicken breasts{2} by placing a hand on top then slicing horizontally to divide in half, stopping about 1/2" from the opposite side so that it can open like a book.
Juice @lemon{1}.
Chop @parsley{1/4%c}.
Drain @capers{1%T}.
Heat @olive oil{2%T} or @olive oil{1%T} and @butter{2%T} in a #large sauté pan{} over med-high heat.
Add @chicken breasts{} and cook ~{3-4%minutes} per side or until done, then remove and set aside.
To the same #pan used for chicken, add @oil{1%tsp}, @garlic{1/2%t}, @capers{}, @salt{} & @pepper{}, then cook ~{30%seconds}.
Add @white wine{1/4%cup} and cook ~{2-3%minutes} or until liquid has mostly reduced.
Add @vegetable base{1%t}, @water{1/2%cup}, @lemon juice{} & @red pepper flakes{1/8%t}, then cook ~{4-6%minutes} or until slightly reduced.
Add @chicken breasts{} back to #pan, stirring to coat and warm through, ~{1-2%minutes}.
Remove from heat and stir in @parsley{}.
== Cook Pasta ==
Add @capellini{8%oz} to boiling @water{} and cook ~{3-5%minutes}, until al dente.
Drain and toss with @butter{1%T} or @olive oil{2%T}.
== Make Salad ==
In a #large bowl, whisk together @Dijon Starter{}, @olive oil{2%T}, @salt{} & @pepper{}.
Remove bottom root, if any, and roughly chop or tear @lettuce{2%c} into bite-sized pieces.
Add @lettuce{} to dressing, tossing to coat.
== Garnish & Gather ==
Divide @pasta{} evenly among plates or #shallow bowls{} and top with @chicken piccata{} & sauce. Serve @salad{} alongside and garnish @pasta{} & @salad{} with @parmesan{3%T}.
+38
View File
@@ -0,0 +1,38 @@
---
title: Chicken Primavera Bake
image: /recipe-images/chicken-primavera-bake.png
---
== Prep ==
Preheat oven to 425°F.
Slice @carrots{6%oz} into thin rounds; slice @button mushrooms{4%oz}. Mince @rosemary{2%tsp} and @chives{2%tsp} separately. Pat @chicken breasts{2} dry, cut into 1-inch pieces, and season with @salt{}.
In a #large bowl{}, whisk together @flour{3/4%cup}(for biscuits), @baking powder{1/2%tbsp}, @baking soda{1/2%tsp}, @sugar{1/2%tsp}, and @salt{1/4%tsp} to form the biscuit dry mix. Keep @butter{2%oz}(for biscuits) cold in the fridge until the biscuit step.
== Cook chicken & vegetables ==
Heat 1 tablespoon @olive oil{} in a #medium ovenproof sauté pan{} over medium-high heat. Add @chicken breasts{} and cook ~{3-4%minutes} until lightly browned; remove and set aside. Chicken will finish cooking in the oven.
Reduce heat to medium, add another tablespoon of @olive oil{}, then add @rosemary{}, @carrots{}, @button mushrooms{}, and @leeks{1/4%cup}(sliced). Cook ~{3-4%minutes} until softened; remove and set aside.
== Build the sauce ==
Add @white wine{1/4%cup} to the pan; cook ~{2-3%minutes} until mostly evaporated.
Add @butter{1%oz}(for sauce) and stir to melt. Add @flour{2%tbsp}(for sauce) and stir constantly ~{1-2%minutes} until incorporated.
Add @chicken broth{3/4%cup} and 1/2 cup water; stir ~{1-2%minutes} until thickened. Return chicken and vegetables to the pan.
Stir in @english peas{1/3%cup} and @mascarpone cheese{2%tbsp}. Season to taste with @salt{} and @pepper{}.
== Make biscuits & bake ==
Stir @chives{} into the biscuit dry mix. Remove cold @butter{2%oz}(for biscuits) from the fridge and grate directly into the bowl with a #box grater{}; toss to coat.
Stir in @ricotta cheese{6%tbsp} and 1/4 cup water with a fork, then knead a few times until no dry bits remain.
Pinch off tablespoon-sized pieces of dough, roll into balls, and arrange on top of the chicken mixture.
Bake ~{15-18%minutes} until biscuits are golden brown. Serve warm directly from the pan.
@@ -0,0 +1,14 @@
---
title: Chicken with Caramelized Onion & Cardamom Rice
source: Jerusalem - Ottolenghi
servings: 4 servings
tags: One Pot, Chicken, Dinner, Middle Eastern, Rice
---
Put @sugar{3%tbsp} and water in a #small saucepan{} and heat until the sugar dissolves. Remove from the heat, add @barberries{2 1/2%tbsp}(or currants), and set aside to soak. If using currants, you do not need to soak them in this way.
Meanwhile, heat half the @olive oil{4%tbsp} in a #large sauté pan with lid{} over medium heat, add @onions{2}(medium, thinly sliced), and cook for ~{10-15%minutes}, stirring occasionally, until the onion has turned a deep golden brown. Transfer the onion to a small bowl and wipe the pan clean.
Place @chicken thighs{2 1/4%lb}(skin-on, bone-in, or 1 whole chicken quartered) in a #large mixing bowl{} and season with 1½ teaspoons each @salt{} and @black pepper{}. Add the remaining @olive oil{4%tbsp}, @cardamom pods{10}, @whole cloves{}, and @cinnamon sticks{2}(broken in two) and use your hands to mix everything together well. Heat the frying pan again and place the chicken and spices in it. Sear for ~{5%minutes} on each side and remove from the pan (this is important as it part-cooks the chicken). The spices can stay in the pan, but don't worry if they stick to the chicken. Remove most of the remaining oil as well, leaving just a thin film at the bottom. Add @basmati rice{1 2/3%cup}, the caramelized @onions{}, 1 teaspoon @salt{}, and plenty of @black pepper{}. Drain the barberries and add them as well. Stir well and return the seared chicken to the pan, pushing it into the rice.
Pour @boiling water{2 1/4%cup} over the rice and chicken, cover the pan, and cook over very low heat for ~{30%minutes}. Take the pan off the heat, remove the lid, quickly place a clean tea towel over the pan, and seal again with the lid. Leave the dish undisturbed for another ~{10%minutes}. Finally, add @parsley{1 1/2%tbsp}(chopped), @dill{1/2%cup}(chopped), and @cilantro{1/4%cup}(chopped) and use a fork to stir them in and fluff up the rice. Taste and add more salt and pepper if needed. Serve hot or warm with @Greek yogurt{1/3%cup}(mixed with 2 tbsp olive oil) if you like.
+59
View File
@@ -0,0 +1,59 @@
---
title: Chili Crisp Beef Lettuce Wraps
subtitle: with crispy rice noodles & cucumber salad
author: Chef Robin Pridgen
servings: 2
time: 35 minutes
prep time: 30 minutes
tags: [beef, lettuce wraps, asian, quick]
allergens: [sesame, soy, wheat]
image: /recipe-images/chili-crisp-beef-lettuce-wraps.png
---
== Prep Veggies & Cook Rice ==
In a #pot, bring @water{1,1/2%cups} and @salt{} to a boil.
Thinly slice @radishes{1/4%c}.
Remove @cilantro{1/4%c} leaves from stems—do not chop.
Trim root from @bibb lettuce{1%head} and separate leaves.
Add @long grain rice{3/4%c} to boiling @water{}, return to a boil, then cover, reduce heat to low and cook ~{12-15%minutes}, until tender.
== Make Cucumber Salad ==
Peel @cucumber{2%c} then cut into 1/4" thick slices on the diagonal.
In a med #bowl, stir @tamari{1/2%T}, @sugar{1/2%T}, @rice vinegar{2%t}, @sesame oil{1%t} to combine -- Cucumber Dressing.
Add @cucumber{}, HALF of @cilantro{}, HALF of @black sesame seeds{1%t} & @salt{} to taste.
== Fry Rice Noodles ==
Break @rice vermicelli{1%oz} in half and separate the strands.
Line a #sheet pan or plate with @paper towels{}.
In a small #pot, heat @oil{1/2%cup} over med.
Test a few strands to make sure oil is hot enough, then working in 3-4 batches (6-8 batches), add a small handful of @rice noodles{} to hot @oil{}, turning with @tongs{}, until puffed—watch carefully, this will happen quickly!
Transfer @rice noodles{} to #paper towels to drain.
== Stir Fry Beef & Finish Rice ==
Stir @hoisin{2%T}, @tamari{1%T}, @honey{1%T}, @rice vinegar{1/4%T}, @garlic{1/4%T}, @diced ginger{1/4%T} to combine -- Beef Starter.
In a #sauté pan, heat @oil{1%Tbsp} over med-high.
Add @ground beef{12%oz}, season lightly with @salt{} & @pepper{}, and cook ~{4-5%minutes}, breaking up with a wooden spoon until browned, then spoon out excess juices.
Add @beef starter{} and cook another ~{2-3%minutes}.
To @rice{}, add remaining @black sesame seeds{} and fluff with a fork.
== Garnish & Gather ==
Serve @ground beef{} & @lettuce leaves{} with @radishes{}, remaining @cilantro{}, crispy @rice noodles{} & @chili crisp{1/4%c}. Enjoy @cucumber salad{} & @rice{} on the side.
+43
View File
@@ -0,0 +1,43 @@
---
title: Cilantro Lime Steak Fajitas
subtitle: with peppers, onions, crema & cotija corn salad
author: Chef Torie Cox
servings: 2
time: 25 minutes
prep time: 20 minutes
cuisine: Mexican
tags:
- steak
- fajitas
- mexican
description: Cilantro lime steak fajitas with peppers, onions, crema, and cotija corn salad.
source: /recipe-images/Scan_20260622_173831.jpg
------
== Make Crema & Prep Veggies ==
Zest and juice the @lime{1}, keeping zest and juice separate. Chop @cilantro{1/4%cup}.
In a #medium bowl{}, stir together @sour cream{1/3%cup}, the lime zest, half of the cilantro, @salt, and @pepper to make the crema. Set aside.
Slice @red pepper{1}(thinly sliced). Slice @onion{1/3%cup}(thinly sliced). Shuck @corn{2%ears} then cut kernels from cobs. Thinly slice @radish{1/2%cup}.
In a separate #medium bowl{}, whisk together @olive oil{1%tbsp}, the lime juice, @salt{}, and @pepper{}. Add the corn, radish, @cotija cheese{2%tbsp}, and remaining cilantro to the lime dressing and toss to combine. Set corn salad aside.
== Cook Fajitas ==
In a #large sauté pan{}, heat @oil{1%tbsp} over med-high. Pat @sliced steak{10%oz} dry then season with half of the @fajita seasoning{} [- 1/2 tsp cumin, 1/2 tsp chili powder -] and @salt{}.
Add beef to hot pan and cook ~{3-5%minutes}, until browned and cooked to desired doneness, then remove from pan and set aside.
In the same #large sauté pan{}, heat another @oil{1/2%tbsp} over med-high. Add the peppers, onions, and remaining fajita seasoning, then cook ~{6-8%minutes} until tender.
== Finish Fajitas & Warm Tortillas ==
Return beef to the pan with the peppers and onions, toss to combine, then season to taste.
Wrap @flour tortillas{4} in a damp paper towel and microwave for ~{30%seconds} to warm.
== Garnish & Gather ==
Serve beef and veggies in tortillas topped with crema, and enjoy the corn salad on the side.
BIN
View File
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
---
title: Crispy Salmon & Cavatappi
description: Crispy salmon and cavatappi with English peas and spring arugula pesto.
servings: 2 servings
tags: Pesto, Italian-American, Salmon, main course, Pasta
image: /recipe-images/crispy-salmon-cavatappi.jpg
---
Remove any large stems from @arugula{1 1/2%cup}. Remove woody stems from @mint{3%tbsp}. Zest and juice half of @lemon{1} and cut the remainder into wedges for garnish.
In a #food processor{} or #blender{}, pulse to combine @arugula{}, @parsley{1/4%cup}, @mint{}, @garlic clove{1}, @sunflower seeds{2%tbsp}, @red pepper flakes{1/8%tsp} (HOT!), and @pecorino cheese{2%tbsp}. Add lemon zest and juice from @lemon{}, then slowly add @olive oil{1/4%cup}. Process until smooth and season with @salt{} and @pepper{} to taste.
Bring a #large pot{} of salted water to a boil for @cavatappi{8%oz}.
Pat @salmon fillets{2} dry and season with @salt{} and @pepper{}. In a #large sauté pan{}, heat 1 tbsp @olive oil{1/4%cup} over medium-high heat. Add @salmon fillets{} skin-side down and cook until skin is crispy, about ~{5%minutes}. Flip salmon and cook another ~{2-3%minutes} or until desired doneness.
Add @cavatappi{} and @peas{1/2%cup} to the boiling water and cook until al dente, ~{3-5%minutes}, then drain, reserving 1/2 cup of the cooking water.
Return drained pasta to the pot along with most of the pesto, 1/3 cup reserved cooking water, and @butter{1%tbsp}, tossing until butter melts and sauce coats pasta well, adding additional pasta water as needed to loosen the sauce. Season to taste.
Divide pasta and salmon among shallow bowls or plates, drizzle with remaining pesto, and garnish with lemon wedges.
+20 -15
View File
@@ -4,7 +4,7 @@
**Goal:** Give every `.cook` recipe file an `image:` field in YAML frontmatter pointing to `https://roux.roo.lol/recipe-images/<slug>.webp`, and download each image locally.
**Architecture:** Three parallel batches — (1) relink the 19 existing images, (2) discover + download + link 48 missing images (recipes with frontmatter), (3) create frontmatter + discover + link 9 more (recipes without frontmatter). Use subagent parallel dispatch for image discovery to keep wall-clock time manageable.
**Architecture:** Three parallel batches — (1) relink the 19 existing images, (2) discover + download + link 50 missing images (recipes with frontmatter), (3) create frontmatter + discover + link 9 more (recipes without frontmatter). Use subagent parallel dispatch for image discovery to keep wall-clock time manageable.
**Tech Stack:** bash, curl, ImageMagick (convert), subagent researcher for web image search
@@ -13,50 +13,56 @@
### Task 0: Setup — slug map, image dir, helper script
**Files:**
- Create: `/home/jbrechtel/recipes/docs/slugs.csv`
- Modify: none yet
- Create: `docs/slugs.csv`
- Create: `docs/has-image.csv`
- Create: `docs/no-image-has-fm.csv`
- Create: `docs/no-fm.csv`
- [ ] **Step 1: Generate slug mapping**
Run a one-liner that prints every `.cook` file with its slugified stem:
Run a one-liner that prints every `.cook` file with its slugified stem, then deduplicate any collisions:
```bash
cd /home/jbrechtel/recipes
cd /home/jbrechtel/recipes/.worktrees/recipe-images
for f in *.cook; do
stem="${f%.cook}"
slug=$(echo "$stem" \
| tr '[:upper:]' '[:lower:]' \
| sed -e 's/[^a-z0-9]/-/g' -e 's/--*/-/g' -e 's/^-//' -e 's/-$//')
echo "$f|$slug"
done > docs/slugs.csv
head docs/slugs.csv
done | awk -F'|' '
{
slug=$2
count[slug]++
if (count[slug] > 1) {
slug = slug "-" count[slug]
}
print $1 "|" slug
}' > docs/slugs.csv
```
Expected: a pipe-delimited CSV like `Alain-Ducase-Bread.cook|alain-ducase-bread`.
Total: 78 unique slugs (6 duplicate pairs get `-2` suffix).
- [ ] **Step 2: Create image directory**
```bash
mkdir -p /home/jbrechtel/recipes/recipe-images
mkdir -p recipe-images
```
- [ ] **Step 3: Classify each recipe**
```bash
cd /home/jbrechtel/recipes
echo "=== Already has image ==="
cd /home/jbrechtel/recipes/.worktrees/recipe-images
while IFS='|' read -r f slug; do
if grep -q "^image:" "$f" 2>/dev/null; then echo "$f|$slug"; fi
done < docs/slugs.csv > docs/has-image.csv
echo "=== Has frontmatter, no image ==="
while IFS='|' read -r f slug; do
if head -1 "$f" 2>/dev/null | grep -q "^---"; then
if ! grep -q "^image:" "$f" 2>/dev/null; then echo "$f|$slug"; fi
fi
done < docs/slugs.csv > docs/no-image-has-fm.csv
echo "=== No frontmatter ==="
while IFS='|' read -r f slug; do
if ! head -1 "$f" 2>/dev/null | grep -q "^---"; then echo "$f|$slug"; fi
done < docs/slugs.csv > docs/no-fm.csv
@@ -64,12 +70,11 @@ done < docs/slugs.csv > docs/no-fm.csv
wc -l docs/has-image.csv docs/no-image-has-fm.csv docs/no-fm.csv
```
Expected: 19 / 48 / 9 lines respectively.
Expected: 19 / 50 / 9 = 78 total.
- [ ] **Step 4: Commit setup**
```bash
cd /home/jbrechtel/recipes
git add docs/slugs.csv docs/has-image.csv docs/no-image-has-fm.csv docs/no-fm.csv
git commit -m "chore: add recipe slug mapping and classification CSVs"
```

Some files were not shown because too many files have changed in this diff Show More