Skip to content

Recipe format

A recipe is one YAML file. The schema is published at /ai/schemas/preset.schema.json and spectro preset validate checks a file against the running kernel: format, metadata vocabulary, algorithm names, parameter names, variables, and the kernel version range.

The file

name: be_halpha_ew            # lowercase snake_case; the identifier users cite
version: 1.0.0                # semantic version of the recipe itself
description: >-
  What is measured and how, in one paragraph.
requires: ">=0.7, <1.0"       # spectro-kernel range the recipe was validated for
metadata:
  kind: campaign              # analysis | reduction | campaign | template
  status: reviewed            # draft | reviewed | reference
  references:                 # mandatory for a campaign recipe
    - "Vollmann & Eversberg 2006, AN 327, 862"
  conventions: "continuum band 6500-6520 Å, 40 Å window around H-alpha"
  author: "BeSS working group"
variables:                    # what depends on the instrument or the observer
  tilt_deg: {type: float, required: true, description: "slit tilt (deg)"}
  half_width: {type: int, default: 6}
steps:                        # the pipeline, in order
  - name: Straighten the slit
    algorithm: correct_tilt_affine
    params: {tilt_deg: "${tilt_deg}"}

name, version, description and steps are required. A recipe with no variables block is a plain preset and runs as is; every preset written before v0.7.0 is still valid.

Variables

Each variable has a type, an optional default, a description, and optionally a list of choices. A variable without a default is required. The shorthand half_width: 6 declares an optional integer with that default.

Type Accepts Example values
int integers, or strings such as "12" from the command line 6
float numbers 0.4
bool booleans, or true/false, yes/no, on/off, 1/0 true
str text "alf Cyg"
path a file or directory path, kept as text /data/bias
list a YAML list, a JSON list such as "[1, 2]", or "a, b" [5852.49, 6266.50]

Values coming from --set name=value are strings and are converted to the declared type; a value outside choices or of the wrong type is refused with the variable's name and description in the message.

Substitution rules

The rules are deliberately small:

  • a parameter whose value is exactly ${name} receives the variable's typed value (a number stays a number, a list stays a list);
  • a string that contains ${name} among other text is interpolated as text (label: "H-${line}"), useful for labels and file names;
  • lists and mappings are walked recursively;
  • every ${name} must be declared in variables, and every declared variable must be used, otherwise validation fails.

Write the token in quotes, "${name}": YAML would otherwise read the braces of {tilt_deg: ${tilt_deg}} as a nested mapping. The quotes change nothing for the kernel, which still passes the typed value.

Profiles

A profile is any YAML mapping of variable name to value. It carries no science, only what is true of one instrument and one observer:

# lhires_lyon.yaml
tilt_deg: 1.1
half_width: 4

Ways to bind values, in increasing priority:

From How
the recipe default of each variable
a profile file spectro pipeline <recipe> --profile lhires_lyon.yaml
the command line --set tilt_deg=1.1 (repeatable)
Python PipelineBuilder().from_preset("be_halpha_ew", {"tilt_deg": 1.1})
MCP run_preset(session_id, "be_halpha_ew", variables={"tilt_deg": 1.1})

Keep your profiles next to your data, one per instrument setup, and reuse them across every recipe: the same alpy600_toulouse.yaml serves the Be star recipe tonight and the nova recipe next month.

requires

The kernel version range the recipe was validated for, with the plain comparison operators (>=, >, <=, <, ==, !=, comma-separated). A recipe whose range excludes the running kernel refuses to build. When a brick used by a recipe changes its own major version (its numbers changed), the recipe author re-validates and bumps the recipe.

Metadata vocabulary

Key Values Meaning
kind analysis, reduction, campaign, template what the recipe is for; a campaign recipe fixes a measurement convention for a community
status draft, reviewed, reference how far the review went (see Share a recipe)
references list of strings the papers the conventions rest on; mandatory for campaign
conventions text the choices that are not fixed by the literature, stated plainly
author, notes, expects, category text free information shown on the recipe page

Validation

spectro preset validate be_halpha_ew.yaml                 # the file alone
spectro preset validate be_halpha_ew.yaml --profile p.yaml # plus your values
spectro preset show be_halpha_ew                           # variables and steps

Validation is what the CI of a recipe collection runs on every contribution. It reports, all at once: a name that is not snake_case, a missing or malformed version, a missing description, an unknown kind or status, a campaign recipe without references, a requires range the kernel does not satisfy, an unknown algorithm, an unknown parameter name, a required parameter that is neither set nor bound to a variable, an undeclared ${token}, an unused variable, and a depends_on that matches no step.

Provenance

When a recipe runs, every brick records itself in the context history as before, and the run closes with one more record:

algorithm    pipeline:be_halpha_ew
version      1.0.0
params       {variables: {...}, n_steps: 4, kernel_version: 0.7.0, source: package:spectro-kernel-recipes}

It is written by Pipeline.execute for every named pipeline built from a file or a config, and carried into every export that serialises the history. Ad-hoc pipelines assembled in Python without a name leave the history exactly as their steps wrote it.

Discovery

spectro presets lists every recipe the kernel can see, in this search order:

  1. the recipes bundled with the kernel;
  2. the directories listed in the SPECTRO_PRESET_PATH environment variable (:-separated on macOS and Linux);
  3. installed packages that register an entry point in the spectro_kernel.presets group (see Share a recipe).

A bundled name always wins over an external one with the same name. A recipe can also be run from a path (spectro pipeline ./my_recipe.yaml). Nothing is ever fetched from the network.