Execution IR
.food.yamlsays what the recipe is. The execution plan says how to execute it. Targets say how a specific machine understands it.
Foodlang separates recipes from execution. Machine and automation targets do not compile from the recipe text directly — they compile through an internal, S88-inspired execution plan:
.food → FoodRecipeAst → FoodExecutionPlan → machine target
.food.yaml → FoodRecipeAst → FoodExecutionPlan → machine target
Because both formats normalize to the same AST and the same execution plan, equivalent KDL and YAML recipes produce equivalent machine output.
What the plan contains
recipe— name and kind (pourover,espresso_milk_drink, …)inputs— ingredients with roles and normalized amounts (oz → ml)requires.capabilities— the capabilities the executor must provideplan— ordered actions (grind,heat_water,dispense_water,wait, …) with parameters, effects, and confirmationss88— a formula plus unit procedures → operations → phases
A brew_profile is expanded into concrete actions: a bloom becomes a
dispense_water + wait, and each pour becomes a dispense_water (+ optional
wait).
See it
foodlang compile examples/ethiopia-pourover.food --target food-exec
foodlang compile examples/ethiopia-pourover.food --target s88
Confirmations & honesty
Actions carry confirmations (assumed, timer, sensor, manual). Until real
device sensors are mapped, the plan uses assumed/timer confirmations and says so
in its warnings. Foodlang does not claim native execution — it produces a plan a
machine runtime can validate, adapt, or run if it supports the required
capabilities.