cooking/.claude/rules/recipe-format.md
Olomana (multica agent) b7c526a784 PWS-13: Make recipe markdown fully control the tabs
Every top-level :::name block is now a tab, shown in file order, so
authors can add custom tabs and reorder them in the markdown. Titles
come from the name or a :::name[Title] label.

The recipe card is an ordinary :::card tab. Its body lists what it
prints (::ingredients, or a block written just for the card), replacing
::card, the fallback to full sections, and its fixed tab position.

All recipes are migrated, with pages and card images unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-11-07 00:34:10 -08:00

3.6 KiB
Raw Blame History

Recipe Markdown Format

Recipes are plain .md files (not MDX) at recipes/[category]/[slug]/[slug].md, parsed with remark + remark-gfm + remark-directive in lib/recipe-content.ts.

Frontmatter Fields

---
title: "Recipe Title"
slug: "recipe-slug"
date: "YYYY-MM-DD"
lastUpdated: "YYYY-MM-DD"
category: "mains"           # free-form string (e.g. "mains", "soups", "desserts")
tags: ["tag1", "tag2"]      # free-form strings (e.g. ["italian", "chicken"])
cookTime: 45                # minutes
prepTime: 20                # minutes
servings: 4
author: "PWS"               # ID from public/authors.json
description: "Short description for SEO and previews"
featured: false
display: true               # set to false to hide without deleting
displayPhoto: "./assets/hero.jpg"
---

Content Structure

The markdown controls the page: every tab is written in the file, in the order it appears, and the renderer adds, removes and reorders nothing.

The body uses generic markdown directives. Each top-level container :::name … ::: is a tab:

  • Any name works, so custom tabs need no code: :::equipment
  • The title comes from the name (:::wine-pairing → "Wine Pairing"); a label overrides it: :::notes[Chef Tips]
  • The body is ordinary markdown. An image's title becomes its caption: ![Alt text](./assets/hero.jpg "Caption")

Standard tabs are :::photos, :::ingredients, :::instructions, :::notes, :::references, and :::card. Only card has reserved behaviour.

Markdown before the first tab renders as intro prose above the tabs; markdown after the last tab renders as outro prose below. Prose between tabs is an error.

Recipe card

:::card[Recipe Card] is a tab showing a printable 5×7 in PNG. Its body lists the one or two sections to print, left to right. ::name reuses another tab, from anywhere in the file:

:::card[Recipe Card]
::ingredients
::instructions
:::

A :::name block inside it is written just for the card, and can be mixed with references. The outer fence then needs four colons:

::::card[Recipe Card]
::ingredients
:::instructions
1. Condensed step one.
2. Condensed step two.
:::
::::

Only what's listed is printed; images, tables and code are left out. The card uses one side when the text fits at 8pt or larger; otherwise it splits into a front (first section) and back (second section). The build fails if even front/back doesn't fit — write shorter content inside :::card.

Validation

Duplicate tab names, a top-level leaf directive (::notes), an invalid card body, and a card listing a missing tab or nothing printable fail the build with the file. Since any name is a valid tab, a typo like :::ingrediants shows up as a misspelled tab rather than an error, and a card listing ::ingredients then fails the build. :word inside prose (e.g. "Tip:Use") is left as literal text.

Example

---
title: "Lentils"
description: "A neutral lentil dish."
...
---

This recipe uses brown lentils (whole Masoor Dal)...

:::photos
![Lentils](./assets/hero.jpg "Finished lentils")
:::

:::ingredients
- 1 cup brown lentils
:::

:::instructions
1. Rinse lentils...
:::

:::notes
### Tips
- Try with different lentils!
:::

:::card[Recipe Card]
::ingredients
::instructions
:::

:::references
- Reference Recipe **[HERE](https://example.com)**
:::

Image Paths

Images use relative paths: ./assets/image.jpg

These are rewritten at render time to /recipes/[category]/[slug]/assets/image.jpg (from frontmatter category and slug, not the folder name).