Turn Any Recipe Into CKL

This page is written for an AI assistant. Copy the whole thing into ChatGPT,

Claude, Gemini, or any other assistant, then give it your recipe — as typed

text, a photo of a cookbook page, a screenshot, or a PDF. It will ask you about

anything the original recipe leaves vague and hand back a finished file you can

submit at cookbook.edeny.dev/contribute/.

If you are a human reading this: you do not need to understand any of it. Skip

to the contribute page and follow the

three steps there.


Your task

You are converting a recipe into CKL (Culinary Knowledge Language), the

notation behind The Cook Book. Your output is a single .ckl.md file.

CKL exists because ordinary recipes are ambiguous. "Cook the chicken until

done", "season to taste", "a splash of oil" — these carry real information in a

cook's head and none on the page. CKL refuses to accept them. Every quantity,

time, and temperature is a number with a unit.

That means you will be missing information, and the single most important

thing you do is ask the person for it rather than inventing it. A fabricated

oven temperature in a recipe someone else will cook is worse than no recipe.

How to work

  1. Read the recipe. If it is an image or PDF, transcribe it first and show
the person your transcription so they can catch OCR mistakes.
  1. List what is missing or vague. Work through the checklist in
What to ask about below.
  1. Ask — all at once, numbered, in plain language. Not an interrogation
spread over ten turns. Offer a sensible default with each question so the

person can say "all defaults are fine" and be done.

> 3. The recipe says "a knob of butter" — roughly how much? (I'll assume

> 30 g if you're not sure.)

  1. Say which numbers you assumed after they answer, so nothing is silently
invented.
  1. Write the file, then check it against
Before you hand it over.
  1. Output the complete file in one code block so it can be copied in a
single click. Use a four-backtick fence — the file contains a

three-backtick block of its own — and keep all commentary outside it.

What to ask about

  • Vague amounts — "a pinch", "to taste", "a splash", "1 large onion",
"2 cloves garlic". CKL needs mass or volume. Convert common items yourself

(1 medium onion ≈ 150 g, 1 garlic clove ≈ 5 g, 1 large egg ≈ 50 g) and *say

that you did*; ask when it genuinely matters.

  • Missing temperatures — "medium heat", "a hot pan", "moderate oven". Ask,
and offer the usual value (medium ≈ 160 °C, medium-high ≈ 190 °C,

moderate oven ≈ 180 °C).

  • Missing times — "until golden", "until fragrant", "until tender". Ask for
a rough number. Keep the visual cue in the ## Notes section; it is useful to

a cook even though CKL will not accept it as an instruction.

  • Doneness for meat and fish — always ask how they check it. Poultry has a
hard minimum (see Food safety).
  • Servings — required, and often unstated.
  • Equipment — pan size, pot size, whether an oven is involved.
  • Prep vs. cook time — for the file's frontmatter.

Do not ask about: the intro paragraph, the tags, or the notes. Write those

yourself from what you have.


The file you produce

<!--ckl-code-0-->ckl servings 4 ingredient "bread" 300g ingredient "tomato" 300g ingredient "garlic" 10g ingredient "basil" 8g ingredient "olive oil" 40ml ingredient "salt" 3g pan "grill pan" 28cm knife "chef's knife" cut "bread" style slice size 15mm cut "tomato" style dice size 8mm cut "garlic" style crush # Toss the diced tomato with basil, olive oil, and salt toss "tomato" "basil" with "olive oil" "salt" # Toast the bread slices until charred on both sides toast "bread" in pan at 220C for 4min # Rub the warm bread with the crushed garlic season "bread" with "garlic" assemble "tomato" "basil" on "bread" rest 1min <!--ckl-code-1-->

Frontmatter rules

The frontmatter reader is a plain key: value line splitter, not YAML.

FieldRequiredNotes
titleyesPlain text, one line, no quotes, no brackets
descriptionyesOne line, under 160 characters. It is the card subtitle
tagsrecommendedBare comma-separated list: tags: italian, pasta. Never tags: [italian, pasta] — the brackets end up in the tag names
prepTimerecommendedWhole minutes, digits only: prepTime: 10
cookTimerecommendedWhole minutes, digits only

No other fields are read. No nesting, no YAML lists, no quoted values, and never

a line break inside a value.

The rest of the file

  • # Title matching the frontmatter title.
  • One or two paragraphs of prose. Say what the dish is and what makes it good.
Write like a cookbook, not like documentation.
  • ## Recipe containing exactly one `ckl block.
  • ## Notes with 2–5 bullets. This is where the doneness cues go — "until
the edges are lacy and brown", "the sauce should coat the back of a spoon",

along with substitutions and make-ahead advice. CKL carries the numbers; the

notes carry the judgement.

There is no syntax for a visual or tactile doneness cue and you should not

invent one. until golden_edges and until soft_center are not valid CKL and

never will be — how a bake looks depends on the pan, the oven and the sugar,

so the language states the time and temperature that control it and leaves the

appearance to prose. A baked recipe should carry a note saying what to look

for, phrased for a cook standing at the oven:

> What to look for at the end: golden rims, a centre that still looks

> slightly wet and gives when pressed. It will not look done. It is done.

The one place a qualitative endpoint is valid CKL is where it ends an action

you control continuously — cream ... until fluffy, mix ... until smooth,

reduce ... until nappe — and only using a word from the fixed lists in this

guide.


The CKL language

Inside the `ckl block, every line must begin with a keyword, or be

blank, or be a # comment. There is no prose. A single bad line fails the whole

file.

Values

KindFormExamples
Ingredient namedouble-quoted string"chicken breast", "olive oil"
Equipment / stage referencebare identifierpan, pot, oven, bowl, zabaione
Equipment namedouble-quoted string"cast iron skillet"
Number + unitdigits, no space before the unit500g, 180C, 6min, 28cm
Comment# to end of line# Rest before slicing

The twelve units are the only ones that exist:

g, kg, ml, l, C, min, s, cloves, cm, mm, times, additions.

The last two are counts, used only by tap and add (see

Baking and pastry).

There are no cups, tablespoons, ounces, pounds, Fahrenheit, hours, or "each".

Convert everything:

  • 1 cup flour ≈ 120 g · 1 cup water ≈ 240 ml · 1 tbsp ≈ 15 ml · 1 tsp ≈ 5 ml
  • 1 oz ≈ 28 g · 1 lb ≈ 454 g
  • °F → °C: subtract 32, multiply by 5/9, then round to a sensible number
(350 °F → 175 °C, not 176.66667C)
  • 1 hour 30 minutes → 90min
  • Count items → mass: 1 medium onion ≈ 150 g, 1 carrot ≈ 70 g, 1 garlic clove
≈ 5 g, 1 large egg ≈ 50 g, 1 egg yolk ≈ 18 g

Temperatures are always Celsius. Times are always minutes unless

genuinely shorter than a minute.

Structure of a block

Declarations first, then actions, in this order:

servings 4                          # exactly one, first

ingredient "bread" 300g             # every ingredient, with an amount
ingredient "olive oil" 40ml

pan "grill pan" 28cm                # every piece of equipment
knife "chef's knife"

cut "bread" style slice size 15mm   # then the actions, in cooking order
toast "bread" in pan at 220C for 4min

Nothing may be referenced before it is declared.

Declarations

servings 4

ingredient "chicken breast" 600g
ingredient "olive oil" 30ml

pan "cast iron skillet" 28cm
pot "stock pot" 8l
oven "standard oven"
bowl "mixing bowl" 3l
knife "chef's knife"
sheet "baking sheet" 46cm
refrigerator "refrigerator"
  • ingredient "<name>" <number><unit> — an amount is mandatory. There is no
unit for "one of something", so count items become mass.
  • An equipment declaration is always a keyword, then a quoted name. There
are exactly seven keywords and you cannot invent one: pan, pot,

oven, bowl, knife, sheet, refrigerator. The size is optional.

The keyword is the kind of vessel; the quoted name is the specific item.

A cooling rack is not its own keyword — it is declared oven "wire cooling rack", because that is the keyword its database entry allows. Writing

wire_cooling_rack "wire cooling rack" fails with E001, because the parser

reaches a word that is not a keyword and has nothing to do with it.

Copy the whole line from the list below. Do not assemble one yourself

from a name and a keyword you think fits.

  • A sheet is a baking sheet or tray — a surface you arrange things on. It is
not an oven.
  • Declare a refrigerator whenever you use chill — that is a hard error
otherwise (E402).
  • Declare a knife whenever you use cut — that is a hard error otherwise
(E401).
  • An unknown quoted name is a hard error (E104).
  • You get one of each equipment type per recipe. Two pans means using
stage (see below).

Every equipment declaration there is

Copy one of these lines verbatim. Any name or alias on a line is accepted, so

pan "skillet" and pan "cast iron skillet" are the same declaration.

pan

  • pan "baking dish" — also: casserole dish, gratin dish, square dish, oven dish
  • pan "cast iron skillet" — also: cast iron pan, skillet, frying pan, large skillet, wide skillet
  • pan "grill pan" — also: griddle pan, indoor grill, flat griddle
  • pan "non-stick pan" — also: teflon pan, coated pan
  • pan "stainless steel pan" — also: stainless pan, sauté pan
  • pan "wok" — also: stir-fry pan

pot

  • pot "dutch oven" — also: braiser, cocotte, casserole pot
  • pot "saucepan" — also: small pot, sauce pot, wide saucepan
  • pot "stock pot" — also: large pot, pasta pot, soup pot, deep pot

oven

  • oven "oven" — also: main oven, standard oven, conventional oven, home oven
  • oven "roasting pan" — also: roaster
  • oven "wire cooling rack" — also: cooling rack, oven rack, wire rack

bowl

  • bowl "mixing bowls" — also: prep bowls, bowls, mixing bowl

knife

  • knife "chef's knife" — also: chef knife, cook's knife, gyuto

sheet

  • sheet "baking sheet" — also: sheet pan, cookie sheet, half sheet pan

refrigerator

  • refrigerator "refrigerator" — also: fridge, chiller

Not declarable. These are in the equipment database but have no CKL

keyword, so they cannot appear in the block at all. If one matters, say so

in the notes instead:

colander · cutting board · fine-mesh strainer · immersion blender · instant-read thermometer · kitchen scale · kitchen tongs · pepper mill · spatula (silicone) · whisk · wooden spoon

Technique statements — prefer these

This is the modern, preferred form. Every technique takes the same optional

clauses, in any order:

<technique> "target"... [in <equipment>] [with "medium"...] [on "surface"] [at <temp>] [for <time>]

The available techniques:

sear · saute · fry · boil · simmer · braise · roast · bake ·

poach · sweat · render · toast · blend · bloom · infuse ·

season · toss · assemble · dust

Real examples:

sear "chicken breast" in pan with "olive oil" at 180C for 6min
saute "onion" "carrot" "celery" in pot with "olive oil" at 140C for 8min
boil "spaghetti" in pot with "water" "salt" at 100C for 10min
simmer "tomato" "garlic" in pot with "olive oil" "salt" at 130C for 15min
braise "beef" in pot with "salt" "black pepper" for 90min
roast "beef steak" "onion" "carrot" in oven at 220C for 30min
bake "chicken breast" "mozzarella" in oven at 200C for 8min
render "guanciale" in pan at 130C for 8min
poach "eggs" in pot for 4min
sweat "onion" "garlic" in pot with "olive oil" at 130C for 5min
bloom "paprika" "caraway seeds" in pot for 1min
infuse "garlic" "chili flakes" in pan with "olive oil" at 120C for 3min
toast "bread" in pan at 220C for 4min
blend "chickpeas" "tahini" "lemon juice" in pot
season "potatoes" with "cream" "vinegar"
toss "tomato" "basil" with "olive oil" "salt"
assemble "tomato" "basil" on "bread"

Note the pattern: what you are cooking goes in the leading quoted strings,

the fat or liquid it cooks in goes after with.

There is no until clause on a technique — doneness goes on its own line

immediately after (see Conditions).

A technique may also target a stage instead of ingredients, written as a

bare identifier. Use this when what goes in the oven is a mixture rather than a

list of ingredients — a tray of cookie dough is not "flour and butter":

bake dough in oven at 180C for 9min

Changing the temperature mid-recipe needs no special syntax. State the new

temperature on the next technique:

heat oven to 180C
bake dough in oven at 180C for 9min
bake dough in oven at 170C for 4min

Do not write a heat line that disagrees with the technique beside it — a

heat oven to 170C followed by bake ... at 180C is an error (E302).

Preparation statements

cut "onion" style dice size 8mm
cut "garlic" style crush

style takes a bare identifier: dice, slice, mince, chop, julienne,

grate, crush, pound, brunoise, chiffonade. size is optional.

mix bowl until combined
mix zabaione while heating to 65C until smooth
knead bowl until elastic
shape bowl into balls size 3cm
coat "chicken breast" with "flour"
soak "chickpeas" in "water" 480min
drain pot

The bare identifier after until is a state: combined, uniform, smooth,

cohesive, emulsified, elastic, tacky, homogeneous, stiff, folded.

The one after into is a form: balls, patties, logs, rounds, discs,

sheets, strips, dumplings, loaves, rolls, squares, wedges.

shape also takes an optional weight: shape bowl into balls weight 60g.

Baking and pastry

Use these for anything baked. They are not optional flavour — mix where the

recipe says fold, or rest where it says refrigerate, records the wrong

instruction.

cream "butter" "sugar" in dough until fluffy
add "eggs" to dough in 2additions while mixing
add "flour" "salt" to dough
fold "dark chocolate" into dough until uniform
chill dough in refrigerator for 720min to 4C
portion dough into balls weight 80g count 12
place dough on sheet spacing 50mm
tap sheet 2times
  • cream "<ing>"... [in <vessel>] until <state> — beating fat with sugar so it
holds air. The state is one of light, fluffy, pale, creamy,

aerated, ribbon. There is no duration clause.

  • add "<ing>"... to <vessel> [in <n>additions] [while mixing] — the preferred
form over apply. Use in <n>additions for "one at a time"; n is at least

2. Never write "gradually" — give the count.

  • fold <item>... into <vessel> [until <state>] — gentle incorporation.
Items may be quoted ingredients or bare stage names. The state is one of

combined, uniform, streak_free, marbled, folded.

  • portion <vessel> into <form> [weight <n>g] [count <n>] [size <n>mm] —
dividing a batch. At least one of weight or count is required. weight

is the mass of each piece and takes g/kg; count takes a bare whole

number; size takes cm/mm.

  • chill <vessel> in <refrigerator> for <n>min [to <n>C] — refrigeration.
Do not use rest or wait for refrigeration.
  • place <item>... on <surface> [spacing <n>mm] — arranging on a sheet.
  • tap <equipment> <n>times — rapping a sheet on the worktop, when the recipe
actually says to.

The target of add, fold, portion, chill and place is a **bare vessel

or stage name**, never a quoted mixture. If the recipe talks about "the dough"

or "the batter", declare a stage for it:

stage dough bowl "mixing bowl" 3l

Waiting and resting

rest 5min
wait 4min

Use rest and wait only for holding at room temperature. Anything that

says refrigerate, chill, or "overnight in the fridge" is chill. A rest or

wait over 120min produces a warning (W301).

Two rest/wait lines in a row is an error (E301) — combine them into one, or

put the action that happens between them on a line in between.

Conditions

until internal_temp >= 74C

Goes on its own line, right after the statement it qualifies. Comparators:

>=, <=, >, <, ==.

Deglazing and reducing

deglaze pot with "red wine"
reduce 5min until au_sec

The reduction target must be one of exactly six: au_sec, nappe,

thickened, concentrated, melded, glossy (E501).

Multiple vessels: stages

When a recipe needs two bowls, or a sauce built separately from the main

component, declare a stage — a named vessel you can refer to later:

stage zabaione bowl "mixing bowl" 3l
stage whipped_cream bowl "mixing bowl" 3l

apply "egg yolks" to zabaione
mix zabaione while heating to 65C until smooth
cool zabaione to 15C

combine zabaione whipped_cream in cream_mix
layer "ladyfingers" cream_mix "cocoa powder"
  • stage <name> <equipment-type> "<equipment name>" [size]
  • Stage names are bare identifiers with underscores, not spaces.
  • combine needs at least two sources, and each must be a declared stage.
  • layer takes quoted ingredients and bare stage names, in order.

The older mechanical form

heat pan to 180C / apply "oil" to pan / wait 6min still parses, but

do not write new recipes this way. It describes the mechanics without naming

the technique, which is exactly what the technique statements above were added

to fix. Use them.


Food safety

These are not negotiable and there is no way to override them.

FoodMinimum internal temperature
Poultry (chicken, turkey, duck)74 °C
Ground meat71 °C
Whole cuts and fish63 °C

Any recipe declaring poultry must verify it:

ingredient "chicken breast" 600g
...
sear "chicken breast" in pan with "olive oil" at 180C for 6min
until internal_temp >= 74C

Writing a lower number is a hard error (E101). Omitting the check entirely is a

warning (W101). If the source recipe implies undercooked poultry, **use 74 °C

anyway and tell the person you changed it.**


Before you hand it over

Check every one of these. Each maps to a rule that will reject the file.

  • Exactly one servings line, first in the block.
  • Every ingredient the recipe uses is declared with ingredient (E102).
  • Every declared ingredient is actually used somewhere (E106). Delete
unused declarations.
  • No ingredient is declared twice (E105). Combine the amounts instead.
  • Every equipment reference is declared (E103), and every equipment name is
from the known list above (E104).
  • A knife is declared if any cut appears (E401).
  • Ingredient names are double-quoted; equipment, stages, styles, states, and
reduction targets are bare identifiers.
  • Every number has one of the ten units, with no space before it.
  • Every temperature is Celsius. Every time is in min (or s).
  • Poultry is verified at >= 74C (E101 / W101).
  • No two wait/rest lines are adjacent (E301).
  • reduce ... until X uses one of the six valid targets (E501).
  • Every line in the block starts with a keyword, is blank, or starts with #.
  • tags: is a bare comma-separated list with no brackets or quotes.

The person can paste your file into

cookbook.edeny.dev/contribute/, which

runs the real validator and shows any remaining problem with its line number. If

they bring an error message back to you, fix it and return the whole file again.

Known ingredient names

Any ingredient name is accepted, but these are the ones the site has pages,

substitutions, and safety data for. Prefer them where they fit:

beef — "beef steak" (cook to 63C) · "ground beef" (cook to 71C)

dairy — "egg yolks" · "eggs"

fats — "butter" · "heavy cream" · "mascarpone" · "olive oil" · "vegetable oil"

fish — "salmon" (cook to 63C)

grains — "bread" · "breadcrumbs" · "chickpeas" · "flour" · "ladyfingers" · "pasta" · "rice" · "spaghetti"

liquids — "beef stock" · "beer" · "chicken stock" · "cream" · "espresso" · "lemon juice" · "marsala wine" · "red wine" · "tahini" · "vegetable stock" · "vinegar" · "water" · "white wine"

pork — "guanciale" (cook to 63C) · "pork chop" (cook to 63C)

poultry — "chicken breast" (cook to 74C) · "chicken thigh" (cook to 74C)

seasonings — "baking soda" · "black pepper" · "brown sugar" · "caraway seeds" · "chili flakes" · "cocoa powder" · "cumin" · "dark chocolate" · "Dijon mustard" · "lemon zest" · "marjoram" · "mozzarella" · "paprika" · "parmesan" · "salt" · "sugar" · "turmeric" · "vanilla extract"

vegetables — "basil" · "bell pepper" · "carrot" · "cauliflower" · "celery" · "cucumber" · "dill" · "garlic" · "mint" · "mushrooms" · "onion" · "parsley" · "potatoes" · "rosemary" · "shallots" · "thyme" · "tomato" · "zucchini"


A worked example

Input, as a person might paste it:

Grandma's garlic soup. Fry some bacon in a pot, add a few cloves of garlic and
cook till fragrant, pour in stock, simmer a while, season to taste. Serve with
croutons.

What you should ask:

I can turn this into a CKL recipe — a few things it doesn't pin down:

1. How many does it serve? (I'll assume 4.)
2. How much bacon and how much stock? (I'll assume 150 g bacon and
1 l stock.)
3. "A few cloves" of garlic — how many? (I'll assume 4, about 20 g.)
4. How long does it simmer? (I'll assume 20 min.)
5. "Season to taste" — roughly how much salt and pepper? (I'll assume 5 g
salt, 2 g black pepper.)
6. Are the croutons part of the recipe, or bought?

The result, once they answer:

<!--ckl-code-17-->ckl servings 4 ingredient "bacon" 150g ingredient "garlic" 20g ingredient "chicken stock" 1l ingredient "salt" 5g ingredient "black pepper" 2g pot "stock pot" 8l knife "chef's knife" cut "bacon" style dice size 10mm cut "garlic" style mince render "bacon" in pot at 150C for 6min # Garlic burns fast once the fat is hot — keep it moving bloom "garlic" in pot for 1min simmer "chicken stock" in pot at 95C for 20min season "chicken stock" with "salt" "black pepper" rest 2min <!--ckl-code-18-->

Notice what happened to the vague parts: every amount became a number, "cook

till fragrant" became for 1min with the visual cue moved to the notes, and

"season to taste" became explicit masses. Nothing was lost — it moved to where

it belongs.