🍳 Foodlang

Specification

Foodlang is a .food.yaml profile built on Open Recipe Format (ORF)-style YAML. A Foodlang document is a valid ORF-style recipe plus an X-foodlang extension block.

The full, authoritative specification lives in SPEC.md in the repository root. This page summarises it.

Looking for the hand-written authoring format? See The .food format for its v0.1 grammar.

The .food authoring format

A .food document has one top-level node:

recipe "Name" {
  ingredients {
    milk 10 oz
  }
  steps {
    pour milk
  }
}

Required: an ingredients block (NAME AMOUNT UNIT per line) and a steps block (ACTION ... per line). Optional: yield AMOUNT UNIT, description TEXT, tag NAME. The flat form (ingredient milk 10 oz, step pour milk) is also accepted.

Use separated amount and unit (standard KDL):

ingredient milk 10 oz   # ✅
step stir 5 sec         # ✅

Not glued tokens:

ingredient milk 10oz    # 🚫
step stir 5s            # 🚫

Base recipe (ORF-compatible)

recipe_name: Simple Latte
yields:
  - amount: 1
    unit: serving
ingredients:
  - coffee grounds:
      amounts:
        - amount: 18
          unit: g
      processing:
        - ground
steps:
  - step: Grind the coffee.

The X-Phases block

When a .food recipe is authored with a phases block, the structured .food.yaml carries those phases in an X-Phases ORF extension block (the X- prefix follows the ORF convention for non-core fields). Each phase is a named stage with optional key=value parameters and positional inputs:

X-Phases:
  - phase: preinfuse
    subject: coffee
    params:
      - { key: pressure, value: 2, unit: bar }
      - { key: flow, value: 2, unit: mlps }
      - { key: time, value: 6, unit: s }
  - phase: brew
    subject: coffee
    output: shot
    params:
      - { key: pressure, value: 9, unit: bar }
      - { key: stop, value: 40, unit: g }
      - { key: max, value: 28, unit: s }
  - phase: build
    subject: cup
    params:
      - { ref: vanilla_syrup }
      - { ref: shot }
      - { ref: stir, value: 5, unit: s }
      - { ref: ice }
      - { ref: milk }

This is the structured equivalent of the .food phases block:

phases {
  preinfuse coffee { pressure 2 bar; flow 2 mlps; time 6 s }
  brew coffee to shot { pressure 9 bar; stop 40 g; max 28 s }
  build cup { vanilla_syrup; shot; stir 5 s; ice; milk }
}

X-Phases round-trips losslessly: .food.food.yaml. A phase has an action, an optional subject (before {), an optional output (after to), and a list of params — each a key/value/unit setting or a ref. Machine targets (e.g. decent, s88, food-exec) read these phases through the execution plan.

The X-foodlang block

X-foodlang:
  version: 0.1
  profiles: [process, appliance, robot, web]
  transformations: []
  equipment: []
  checks: []
  appliance_targets: {}
  robot: {}
  industrial: {}
  exports: {}

Transformations

The core concept — typed inputs become typed outputs.

- id: extract_espresso
  type: extraction
  inputs:
    - ingredient: coffee grounds
      state: ground
      amount: { value: 18, unit: g }
    - ingredient: water
      state: hot
      amount: { value: 40, unit: mL }
  outputs:
    - ingredient: espresso
      state: brewed
      amount: { value: 40, unit: mL }
  parameters:
    temperature: { value: 93, unit: Cel }

Equipment, checks, targets

  • equipment{ id, name, capabilities[] }.
  • checks{ id, description, required?, expression?, on_fail }.
  • appliance_targetsopcua, home_connect, mqtt, matter (mappings).
  • robot.action_graph — DAG of { id, action, depends_on?, inputs?, outputs? }.
  • industrial.s88procedure[] of { operation, phases[] }.
  • exports — boolean hints of intended outputs.

Validation levels

Level Name
0 readable
1 parseable
2 structured ingredients
3 process-aware
4 appliance-mappable
5 robot-plannable
6 industrial-mappable

Each level reports pass, partial, or fail.