A static recipe library hosted on GitHub Pages. Recipes are plain markdown files
committed to the repo; a GitHub Action compiles them into index.json after every
push; the site reads that file and does client-side search with no backend.
transcribe in Claude → ./add-recipe.sh → git push → Actions rebuild → site updates
repo/
├── recipes/ ← one .md file per recipe (source of truth)
│ └── chicken-mushroom-risotto.md
├── index.json ← auto-generated by CI, do not edit by hand
├── index.html ← the entire site: search, library, detail view
├── scripts/
│ ├── build-index.js ← parses recipes/ → index.json (run by CI)
│ ├── validate.js ← previews and validates a single recipe file
│ └── test-grocery.js ← regression tests for ingredient parsing/consolidation
├── .github/workflows/
│ └── build.yml ← triggers build-index.js on push to recipes/
└── add-recipe.sh ← CLI helper: validate → preview → commit → push
No build step. No npm. No dependencies. index.html is a single vanilla JS file.
build-index.js uses only Node built-ins (fs, path). Node must be installed locally
to run the helper scripts, but the live site needs nothing beyond a static file host.
git clone git@github.com:you/recipes.git
cd recipes
# copy all files from this package into the repo root
git add .
git commit -m "init recipe library"
git pushIn the repo on github.com:
Settings → Pages → Source → Deploy from branch → main / (root)
Your site will be live at https://you.github.io/recipes/ within a minute or two.
chmod +x add-recipe.shOpen the Claude recipe library artifact. Use the Add Recipe tab:
- Drop in 1–2 photos of a recipe card (HEIC or JPEG)
- Image 1: front of card (ingredients)
- Image 2: back of card (steps + photos)
- Hit Transcribe Recipe — Claude reads both sides and produces markdown
- Review in the editor, make any tweaks
- Copy the markdown to a
.mdfile on your computer
Alternatively, write or paste recipe markdown directly if you already have it.
./add-recipe.sh ~/Desktop/lemon-pasta.mdThe script:
- Copies the file into
recipes/if it isn't there already - Validates and previews — shows parsed title, tags, time, serves, step names, and any warnings or errors
- Prompts before committing:
c— commit and pushe— open$EDITORfor fixes, then re-validatea— abort (removes the copied file)
- Pushes via SSH once you confirm
GitHub Actions runs build-index.js, regenerates index.json, and commits it back.
The site updates automatically. No manual deploy step.
If you've dropped several .md files into recipes/ manually and want to commit them
all at once:
./add-recipe.shThis validates every new or modified file in recipes/, shows the results, and
commits + pushes only if all pass. Any file with errors blocks the whole batch.
# Recipe Title
tags: protein, vegetable, cuisine-style, cooking-method
time: 40min
serves: 2
source: HelloFresh
## Ingredients
- amount ingredient
- amount ingredient
## Steps
### 1. Step Name
- action detail
- action detail
### 2. Step Name
- action detailField reference:
| Field | Required | Notes |
|---|---|---|
# Title |
✓ | Synthesise from the dish if the card is cropped |
tags: |
✓ | Main protein, key veg, cuisine, cooking method |
time: |
recommended | e.g. 40min |
serves: |
recommended | e.g. 2 or 2–4 |
source: |
optional | Meal kit brand if known (HelloFresh, Blue Apron, etc.) |
Filename: kebab-case-recipe-title.md
The validator will warn if the filename doesn't match the title slug.
Tags guidance: derive from main proteins, key vegetables, cuisine style, and cooking
method. More is better for search — chicken, mushroom, arugula, risotto, arborio-rice, parmesan, italian is preferable to just chicken, italian. Tags are comma-separated
and power the site's search ranking (tag matches outrank full-text matches).
validate.js (called automatically by add-recipe.sh) distinguishes:
Errors — must fix before import:
- No
# Titleheading - No
## Ingredientssection - No
## Stepssection - Ingredients section is empty
- No
### N. Step Nameheadings in Steps
Warnings — review but can commit through:
- Missing or sparse
tags: - Missing
time:orserves: - Missing
source:(this is often intentional) - Filename doesn't match the title slug
- Very few ingredients (suggests incomplete transcription)
Run it standalone on any file:
node scripts/validate.js recipes/my-recipe.mdExit code 0 = valid (possibly with warnings). Exit code 1 = errors to fix.
Visit https://you.github.io/recipes/ from any browser, no login required.
- Library — all recipes as cards showing title, time, serves, source, and tags
- Search — filters by title, tags, and full text; tag matches rank higher
- Detail — full rendered recipe with ingredient list and steps
- Random — picks a recipe at random from the library
- Grocery list — select up to 5 recipes, click "Shopping List →" for a consolidated, printable checklist; duplicate ingredients are merged and quantities summed where possible
Keyboard shortcuts: / to focus the search box, Esc to return to the library.
To browse the site locally before pushing:
# Any static file server works — Python is usually already installed:
python3 -m http.server
# Or with Node:
npx serve .Then open http://localhost:8000.
To rebuild index.json locally after editing recipe files:
node scripts/build-index.jsIf you're on a machine without the repo checked out (e.g. your wife's computer), you can add a recipe entirely through the GitHub web UI:
- Go to the repo on github.com
- Navigate to
recipes/ - Click Add file → Create new file
- Name it
kebab-case-title.md, paste the markdown, commit - GitHub Actions rebuilds
index.jsonautomatically